AMBARI-18991 Fix Flume agents table. (ababiichuk)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5c002c64 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5c002c64 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5c002c64 Branch: refs/heads/branch-feature-AMBARI-18634 Commit: 5c002c6408d74b9d7c1a7693f3d01761ed64265a Parents: 549d7cc Author: ababiichuk <ababiic...@hortonworks.com> Authored: Fri Nov 25 18:34:52 2016 +0200 Committer: ababiichuk <ababiic...@hortonworks.com> Committed: Fri Nov 25 19:00:10 2016 +0200 ---------------------------------------------------------------------- ambari-web/app/models/service/flume.js | 8 + ambari-web/app/styles/application.less | 112 ++++------- .../app/styles/theme/bootstrap-ambari.css | 25 ++- .../templates/main/service/services/flume.hbs | 196 ++++++++----------- .../app/views/main/service/services/flume.js | 32 +-- ambari-web/test/models/service/flume_test.js | 6 + .../views/main/service/services/flume_test.js | 17 +- 7 files changed, 178 insertions(+), 218 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/app/models/service/flume.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/service/flume.js b/ambari-web/app/models/service/flume.js index d482ab6..37cfbb5 100644 --- a/ambari-web/app/models/service/flume.js +++ b/ambari-web/app/models/service/flume.js @@ -49,6 +49,14 @@ App.FlumeAgent = DS.Model.extend({ UNKNOWN: App.healthIconClassYellow }, + healthIconClass: Em.computed.getByKey('healthIconClassMap', 'status', ''), + + healthIconClassMap: { + RUNNING: 'health-status-LIVE', + NOT_RUNNING: 'health-status-DEAD-RED', + UNKNOWN: 'health-status-DEAD-YELLOW' + }, + displayStatus: Em.computed.getByKey('displayStatusMap', 'status', Em.I18n.t('common.unknown')), displayStatusMap: { http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index 7d93778..d449ccb 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -2180,86 +2180,60 @@ input[type="radio"].align-checkbox, input[type="checkbox"].align-checkbox { } #flume-summary { - text-align:left !important; max-height: 490px; - #flume-agents-table { + .table { margin: 0; - width: 100%; - .highlight { - td, th { - background-color: #BDC3C7 !important; - color: #666; + table-layout: fixed; + } + #flume-agents-table { + border-collapse: separate; + > tbody > tr > td { + &:last-of-type { + padding: 0; + &.empty-label { + padding: 8px; + text-align: center; + } } } th:first-child { width: 40%; + + th { + width: 30%; + ~ th { + width: 10%; + } + } } - th:first-child + th { - width: 30%; - } - th:first-child + th + th { - width: 10%; - } - th:first-child + th + th + th { - width: 10%; - } - th:first-child + th + th + th + th { - width: 10%; - } - td.agent-status { - width: 125px; - } - td.agent-name { - width: 20%; - overflow: hidden; - } - td.agent-host-name { - width: 20%; - overflow: hidden; - max-width: 90px; - } - .glyphicon-warning-sign { - color: @restart-indicator-color; - } - #flume-host-agent-row { - cursor: pointer; - text-align: left; - background-color: #fff; - } - .empty-label { - border-top: 1px solid #ddd; - text-align: center; - } - } - .wrapp-flume-status{ - text-align: left; - } - .btn-wrapper { - margin: 0 5px 5px 0; - float: right; - width:60px; - position: static; - } - .flume-agents-actions { - .btn-group { - position: static; - } - a { - text-decoration: none; - } - a.dropdown-toggle { - padding: 2px 6px; - font-size: 11px; - line-height: 17px; - } - .dropdown-menu { - position: absolute; + td { + &.agent-host-name { + overflow: hidden; + border-bottom: 1px solid #eee; + cursor: pointer; + } + &.agent-status { + width: 50%; + } + &.flume-agent-sources-count, &.flume-agent-channels-count { + width: 16.667%; + } + &.flume-agent-sink-count { + width: 16.666%; + } + .flume-agents-actions { + .btn-group { + position: static; + } + a { + text-decoration: none; + } + } } } .scrollable-container { + position: static; max-height: 450px; - width: 100%; - overflow-y: scroll; + overflow-y: auto; } } http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/app/styles/theme/bootstrap-ambari.css ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/theme/bootstrap-ambari.css b/ambari-web/app/styles/theme/bootstrap-ambari.css index fd341a5..f427c0a 100644 --- a/ambari-web/app/styles/theme/bootstrap-ambari.css +++ b/ambari-web/app/styles/theme/bootstrap-ambari.css @@ -35,7 +35,6 @@ outline: none; font-family: 'Roboto', sans-serif; text-transform: uppercase; - height: 34px; font-size: 14px; padding: 10px 20px; line-height: 14px; @@ -213,6 +212,10 @@ background-color: #429929; border: 1px solid #3FAE2A; } +.navbar-btn { + margin-top: 7px; + margin-bottom: 7px; +} .btn-regular-default-state { background-color: #FFF; color: #666; @@ -374,8 +377,21 @@ h2.table-title { top: 4px; margin-bottom: 0; } +.table thead > tr > th { + border-bottom-color: #EEE; +} .table tfoot > tr:first-of-type > td { border-top-width: 2px; + border-top-color: #EEE; +} +.table > tbody > tr > td { + border-top-color: #EEE; +} +.table > tbody > tr.active { + background-color: #EEE; +} +.table > tbody > tr.active > td { + background-color: #EEE; } .table.table-hover .action { visibility: hidden; @@ -393,13 +409,6 @@ h2.table-title { .table.table-hover > tbody > tr > td { border-width: 0; } -.table.table-hover > tbody > tr.active { - border-color: #EEE; - background-color: #EEE; -} -.table.table-hover > tbody > tr.active > td { - background-color: #EEE; -} .table.table-hover > tbody > tr:hover { border-color: #A7DFF2; background-color: #E7F6FC; http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/app/templates/main/service/services/flume.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/service/services/flume.hbs b/ambari-web/app/templates/main/service/services/flume.hbs index 1e57cd5..5b3a8e2 100644 --- a/ambari-web/app/templates/main/service/services/flume.hbs +++ b/ambari-web/app/templates/main/service/services/flume.hbs @@ -21,121 +21,89 @@ <div class="col-md-12"> <a href="#" {{action filterHosts view.flumeHandlerComponent}}>{{view.summaryHeader}}</a> <a href="#" class="pull-right" {{action gotoConfigs target="controller"}}>{{t dashboard.services.flume.summary.configure}}</a> - <div id="flume-agent-table-wrap" class="scrollable-container"> - <table class="table table-hover advanced-header-table table-bordered table-striped" id="flume-agents-table"> - <thead> - {{#view view.sortView contentBinding="view.filteredContent" class="label-row"}} - {{view view.parentView.hostSort}} - <th>{{t dashboard.services.flume.agent}}</th> - <th> - <i class="glyphicon glyphicon-signin" {{translateAttr title="dashboard.services.flume.sources"}}></i> {{t dashboard.services.flume.sources}} - </th> - <th> - <i class="glyphicon glyphicon-random" {{translateAttr title="dashboard.services.flume.channels"}}></i> {{t dashboard.services.flume.channels}} - </th> - <th> - <i class="glyphicon glyphicon-signout" {{translateAttr title="dashboard.services.flume.sinks"}}></i> {{t dashboard.services.flume.sinks}} - </th> - {{/view}} - </thead> - {{#if view.pageContent}} - {{#each host in view.pageContent}} - <tbody class="flume-agent-table-tbody"> - {{#view view.agentView contentBinding="host"}} - <td {{bindAttr rowspan="host.rowspan"}} id="flume-host-agent-row" class="agent-host-name"> - <a class="agent-host-link" href="javascript:void(null)" {{action click host target="view"}}> - {{host.hostName}} - </a> - </td> - <td class="agent-status"> - <div class="wrapp-flume-status"> - <div class="pull-left flume-agents-status"> - <span {{bindAttr class="host.firtstAgent.healthClass"}}></span> {{host.firtstAgent.name}}</div> - <div class="btn-wrapper flume-agents-actions"> - <div class="btn-group display-inline-block"> - <a class="btn btn-default dropdown-toggle" data-toggle="dropdown" - href="javascript:void(null)">{{host.firtstAgent.displayStatus}} - <span class="caret"></span> - </a> - <ul class="pull-left dropdown-menu"> - <li {{bindAttr class="host.firtstAgent.isStartAgentDisabled:disabled"}}> - <a href="javascript:void(null)" - {{bindAttr class="host.firtstAgent.isStartAgentDisabled:disabled :start-agent"}} - {{action startFlumeAgent host.firtstAgent target="controller"}}> - {{t services.service.summary.flume.startAgent}}</a> - </li> - <li {{bindAttr class="host.firtstAgent.isStopAgentDisabled:disabled"}}> - <a href="javascript:void(null)" - {{bindAttr class="host.firtstAgent.isStopAgentDisabled:disabled :stop-agent"}} - {{action stopFlumeAgent host.firtstAgent target="controller"}}> - {{t services.service.summary.flume.stopAgent}}</a> - </li> - </ul> - </div> - </div> - </div> - </td> - <td class="flume-sources-count"> - {{host.firtstAgent.sourcesCount}} - </td> - <td class="flume-channels-count"> - {{host.firtstAgent.channelsCount}} - </td> - <td class="flume-sinks-count"> - {{host.firtstAgent.sinksCount}} - </td> - {{/view}} - {{#each agent in host.otherAgents}} - {{#view view.agentView contentBinding="host"}} - <td class="agent-status"> - <div class="wrapp-flume-status"> - <div class="pull-left flume-agents-status"> - <span {{bindAttr class="agent.healthClass"}}></span> {{agent.name}}</div> - <div class="btn-wrapper flume-agents-actions"> - <div class="btn-group display-inline-block"> - <a class="btn btn-default dropdown-toggle" data-toggle="dropdown" - href="javascript:void(null)">{{agent.displayStatus}} - <span class="caret"></span> - </a> - <ul class="pull-left dropdown-menu"> - <li {{bindAttr class="agent.isStartAgentDisabled:disabled :start-agent"}}> - <a href="javascript:void(null)" - {{bindAttr class="agent.isStartAgentDisabled:disabled"}} - {{action startFlumeAgent agent target="controller"}}> - {{t services.service.summary.flume.startAgent}}</a> - </li> - <li {{bindAttr class="agent.isStopAgentDisabled:disabled"}}> - <a href="javascript:void(null)" - {{bindAttr class="agent.isStopAgentDisabled:disabled :stop-agent"}} - {{action stopFlumeAgent agent target="controller"}}> - {{t services.service.summary.flume.stopAgent}}</a> - </li> - </ul> - </div> - </div> - </div> - </td> - <td class="flume-agent-sources-count"> - {{agent.sourcesCount}} - </td> - <td class="flume-agent-channels-count"> - {{agent.channelsCount}} - </td> - <td class="flume-agent-sink-count"> - {{agent.sinksCount}} - </td> - {{/view}} - {{/each}} - </tbody> - {{/each}} - {{else}} - <tr> - <td colspan="5" id="flume-agents-empty-label" class="empty-label"> - {{t services.service.summary.flume.noAgents}} + </div> + <div id="flume-agent-table-wrap" class="scrollable-container col-md-12"> + <table class="table advanced-header-table" id="flume-agents-table"> + <thead> + {{#view view.sortView contentBinding="view.filteredContent" class="label-row"}} + {{view view.parentView.hostSort}} + <th>{{t dashboard.services.flume.agent}}</th> + <th> + <i class="icon icon-signin" {{translateAttr title="dashboard.services.flume.sources"}}></i> {{t dashboard.services.flume.sources}} + </th> + <th> + <i class="icon icon-random" {{translateAttr title="dashboard.services.flume.channels"}}></i> {{t dashboard.services.flume.channels}} + </th> + <th> + <i class="icon icon-signout" {{translateAttr title="dashboard.services.flume.sinks"}}></i> {{t dashboard.services.flume.sinks}} + </th> + {{/view}} + </thead> + <tbody> + {{#if view.pageContent}} + {{#each host in view.pageContent}} + <tr {{bindAttr class="host.isActive:active"}}> + <td class="agent-host-name" {{action selectHost host target="view"}}> + <a href="javascript:void(null)"> + {{host.hostName}} + </a> + </td> + <td colspan="4"> + <table class="table table-hover table-striped"> + <tbody> + {{#each agent in host.agents}} + <tr {{bindAttr class="host.isActive:active"}}> + <td class="agent-status"> + <div class="pull-left"> + <span {{bindAttr class="agent.healthClass agent.healthIconClass"}}></span> {{agent.name}} + </div> + <div class="flume-agents-actions pull-right"> + <div class="btn-group display-inline-block"> + <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> + {{agent.displayStatus}} + <span class="caret"></span> + </button> + <ul class="pull-left dropdown-menu"> + <li {{bindAttr class="agent.isStartAgentDisabled:disabled :start-agent"}}> + <a href="javascript:void(null)" + {{bindAttr class="agent.isStartAgentDisabled:disabled"}} + {{action startFlumeAgent agent target="controller"}}> + {{t services.service.summary.flume.startAgent}}</a> + </li> + <li {{bindAttr class="agent.isStopAgentDisabled:disabled"}}> + <a href="javascript:void(null)" + {{bindAttr class="agent.isStopAgentDisabled:disabled :stop-agent"}} + {{action stopFlumeAgent agent target="controller"}}> + {{t services.service.summary.flume.stopAgent}}</a> + </li> + </ul> + </div> + </div> + </td> + <td class="flume-agent-sources-count"> + {{agent.sourcesCount}} + </td> + <td class="flume-agent-channels-count"> + {{agent.channelsCount}} + </td> + <td class="flume-agent-sink-count"> + {{agent.sinksCount}} + </td> + </tr> + {{/each}} + </tbody> + </table> </td> </tr> - {{/if}} - </table> - </div> + {{/each}} + {{else}} + <tr> + <td colspan="5" class="empty-label"> + {{t services.service.summary.flume.noAgents}} + </td> + </tr> + {{/if}} + </tbody> + </table> </div> </div> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/app/views/main/service/services/flume.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/service/services/flume.js b/ambari-web/app/views/main/service/services/flume.js index 2db4583..15c61d6 100644 --- a/ambari-web/app/views/main/service/services/flume.js +++ b/ambari-web/app/views/main/service/services/flume.js @@ -37,10 +37,7 @@ App.MainDashboardServiceFlumeView = App.TableView.extend(App.MainDashboardServic content.push( Em.Object.create({ hostName: hostName, - agents: agents, - rowspan: agents.length, - firtstAgent: agents[0], - otherAgents: agents.without(agents[0]) + agents: agents }) ); }); @@ -58,24 +55,6 @@ App.MainDashboardServiceFlumeView = App.TableView.extend(App.MainDashboardServic componentName: 'FLUME_HANDLER' }), - agentView: Em.View.extend({ - content: null, - tagName: 'tr', - - click: function (e) { - var numberOfAgents = this.get('content.agents').length; - if ($(e.target).attr('class') === "agent-host-name" || $(e.target).attr('class') === "agent-host-link") { - var currentTargetRow = $(e.currentTarget); - if ($(e.target).attr('class') === "agent-host-link") { - currentTargetRow = currentTargetRow.parent(".agent-host-name").parent(); - } - currentTargetRow.parents("table:first").find('tr').removeClass('highlight'); - currentTargetRow.addClass('highlight').nextAll("tr").slice(0, numberOfAgents - 1).addClass('highlight'); - this.get('parentView').showAgentInfo(this.get('content')); - } - } - }), - sortView: sort.wrapperView, hostSort: sort.fieldView.extend({ @@ -92,6 +71,14 @@ App.MainDashboardServiceFlumeView = App.TableView.extend(App.MainDashboardServic }); }, + selectHost: function (e) { + var host = e && e.context; + this.get('pageContent').setEach('isActive', false); + if (host) { + this.showAgentInfo(host); + } + }, + /** * Locate dropdown menu absolutely outside of scrollable block * @param element @@ -131,6 +118,7 @@ App.MainDashboardServiceFlumeView = App.TableView.extend(App.MainDashboardServic * @param {object} host */ showAgentInfo: function (host) { + Em.set(host, 'isActive', true); this.set('selectedHost', host); this.setAgentMetrics(host); }, http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/test/models/service/flume_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/models/service/flume_test.js b/ambari-web/test/models/service/flume_test.js index 55fd135..d88f375 100644 --- a/ambari-web/test/models/service/flume_test.js +++ b/ambari-web/test/models/service/flume_test.js @@ -47,6 +47,12 @@ describe('App.FlumeAgent', function () { UNKNOWN: App.healthIconClassYellow }}); + App.TestAliases.testAsComputedGetByKey(getModel(), 'healthIconClass', 'healthIconClassMap', 'status', {defaultValue: '', map: { + RUNNING: 'health-status-LIVE', + NOT_RUNNING: 'health-status-DEAD-RED', + UNKNOWN: 'health-status-DEAD-YELLOW' + }}); + App.TestAliases.testAsComputedGetByKey(getModel(), 'displayStatus', 'displayStatusMap', 'status', {defaultValue: Em.I18n.t('common.unknown'), map: { RUNNING: Em.I18n.t('common.running'), NOT_RUNNING: Em.I18n.t('common.stopped'), http://git-wip-us.apache.org/repos/asf/ambari/blob/5c002c64/ambari-web/test/views/main/service/services/flume_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/views/main/service/services/flume_test.js b/ambari-web/test/views/main/service/services/flume_test.js index a19b5c9..dc2f99a 100644 --- a/ambari-web/test/views/main/service/services/flume_test.js +++ b/ambari-web/test/views/main/service/services/flume_test.js @@ -40,8 +40,6 @@ describe('App.MainDashboardServiceFlumeView', function () { ]); view.propertyDidChange('content'); expect(view.get('content').mapProperty('hostName')).to.be.eql(['host1', 'host2']); - expect(view.get('content').mapProperty('rowspan')).to.be.eql([1, 2]); - expect(view.get('content').mapProperty('firtstAgent')).to.be.eql([{hostName: 'host1'}, {hostName: 'host2'}]); }); }); @@ -162,18 +160,27 @@ describe('App.MainDashboardServiceFlumeView', function () { describe("#showAgentInfo()", function() { + var host; + beforeEach(function() { + host = {hostName: 'host1'}; sinon.stub(view, 'setAgentMetrics'); + view.showAgentInfo(host); }); afterEach(function() { view.setAgentMetrics.restore(); }); - it("setAgentMetrics should be called", function() { - var host = {hostName: 'host1'}; - view.showAgentInfo(host); + it('setAgentMetrics should be called', function() { expect(view.setAgentMetrics.calledWith(host)).to.be.true; + }); + + it('proper host should be selected', function() { expect(view.get('selectedHost')).to.be.eql(host); }); + + it('proper row should be highlighted', function() { + expect(Em.get(host, 'isActive')).to.be.true; + }); }); }); \ No newline at end of file