This is an automated email from the ASF dual-hosted git repository.

cwylie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 96b9b30  Web console: Adding a server view that can display all 
servers (#7770)
96b9b30 is described below

commit 96b9b3073cb350e6ee44625327134384de899820
Author: Vadim Ogievetsky <[email protected]>
AuthorDate: Tue May 28 17:12:50 2019 -0700

    Web console: Adding a server view that can display all servers (#7770)
    
    * adding a server view that can see all servers
    
    * fixing action-cell snapshot test
    
    * dynamic resize on sql view
    
    * remove extra word
    
    * update home view server tile also
    
    * offer more context options
    
    * pass context to explain also
---
 web-console/package.json                           |   2 +-
 web-console/src/bootstrap/react-table-defaults.tsx |   4 +-
 .../__snapshots__/action-cell.spec.tsx.snap        |  22 +-
 .../components/action-cell/action-cell.spec.tsx    |   8 +-
 .../src/components/action-cell/action-cell.tsx     |  27 +-
 .../__snapshots__/header-bar.spec.tsx.snap         |   2 +-
 .../src/components/header-bar/header-bar.scss      |   4 +-
 .../src/components/header-bar/header-bar.tsx       |   2 +-
 .../__snapshots__/sql-control.spec.tsx.snap        | 134 ++--
 .../src/components/sql-control/sql-control.scss    |  24 +-
 .../components/sql-control/sql-control.spec.tsx    |  15 +-
 .../src/components/sql-control/sql-control.tsx     | 129 ++--
 .../view-control-bar/view-control-bar.scss         |   4 +-
 web-console/src/console-application.scss           |   2 +-
 web-console/src/entry.scss                         |   2 +
 web-console/src/utils/general.tsx                  |  12 +-
 web-console/src/utils/ingestion-spec.tsx           |  41 +-
 web-console/src/utils/local-storage-keys.tsx       |   4 +-
 web-console/src/variables.scss                     |   2 +
 .../__snapshots__/datasource-view.spec.tsx.snap    |   2 +-
 .../src/views/datasource-view/datasource-view.scss |   4 +-
 .../src/views/datasource-view/datasource-view.tsx  |  30 +-
 .../__snapshots__/home-view.spec.tsx.snap          |   2 +-
 web-console/src/views/home-view/home-view.tsx      | 297 ++++----
 .../src/views/load-data-view/load-data-view.tsx    |   9 +-
 .../__snapshots__/lookups-view.spec.tsx.snap       |   2 +-
 .../src/views/lookups-view/lookups-view.tsx        |  26 +-
 .../__snapshots__/segments-view.spec.tsx.snap      |   2 +-
 .../src/views/segments-view/segments-view.scss     |   4 +-
 .../src/views/segments-view/segments-view.tsx      |   3 +-
 .../__snapshots__/servers-view.spec.tsx.snap       | 773 ++++++++-------------
 .../src/views/servers-view/servers-view.scss       |  18 +-
 .../src/views/servers-view/servers-view.tsx        | 512 +++++++-------
 .../sql-view/__snapshots__/sql-view.spec.tsx.snap  | 297 ++++----
 web-console/src/views/sql-view/sql-view.scss       |  36 +-
 web-console/src/views/sql-view/sql-view.tsx        | 107 +--
 .../__snapshots__/tasks-view.spec.tsx.snap         |   6 +-
 web-console/src/views/task-view/tasks-view.scss    |  36 +-
 web-console/src/views/task-view/tasks-view.tsx     | 104 ++-
 39 files changed, 1298 insertions(+), 1412 deletions(-)

diff --git a/web-console/package.json b/web-console/package.json
index 2191296..4cf6311 100644
--- a/web-console/package.json
+++ b/web-console/package.json
@@ -31,7 +31,7 @@
     "run": "./script/run",
     "test": "jest --silent 2>&1",
     "coverage": "jest --coverage",
-    "update": "jest -u",
+    "update-snapshots": "jest -u",
     "tslint": "./node_modules/.bin/tslint -c tslint.json --project 
tsconfig.json --formatters-dir ./node_modules/awesome-code-style/formatter 
'src/**/*.ts?(x)'",
     "tslint-fix": "npm run tslint -- --fix",
     "tslint-changed-only": "git diff --diff-filter=ACMR --cached --name-only | 
grep -E \\.tsx\\?$ | xargs ./node_modules/.bin/tslint -c tslint.json --project 
tsconfig.json --formatters-dir ./node_modules/awesome-code-style/formatter",
diff --git a/web-console/src/bootstrap/react-table-defaults.tsx 
b/web-console/src/bootstrap/react-table-defaults.tsx
index b4dde83..d68912b 100644
--- a/web-console/src/bootstrap/react-table-defaults.tsx
+++ b/web-console/src/bootstrap/react-table-defaults.tsx
@@ -37,6 +37,7 @@ class NoData extends React.Component {
 /* tslint:enable:max-classes-per-file */
 
 Object.assign(ReactTableDefaults, {
+  className: '-striped -highlight',
   defaultFilterMethod: (filter: Filter, row: any, column: any) => {
     const id = filter.pivotId || filter.id;
     return booleanCustomTableFilter(filter, row[id]);
@@ -51,5 +52,6 @@ Object.assign(ReactTableDefaults, {
     const previewValues = subRows.filter((d: any) => typeof d[column.id] !== 
'undefined').map((row: any) => row[column.id]);
     const previewCount = countBy(previewValues);
     return <span>{Object.keys(previewCount).sort().map(v => `${v} 
(${previewCount[v]})`).join(', ')}</span>;
-  }
+  },
+  defaultPageSize: 20
 });
diff --git 
a/web-console/src/components/action-cell/__snapshots__/action-cell.spec.tsx.snap
 
b/web-console/src/components/action-cell/__snapshots__/action-cell.spec.tsx.snap
index f3a8876..e1c819e 100644
--- 
a/web-console/src/components/action-cell/__snapshots__/action-cell.spec.tsx.snap
+++ 
b/web-console/src/components/action-cell/__snapshots__/action-cell.spec.tsx.snap
@@ -4,8 +4,24 @@ exports[`describe action cell action cell snapshot 1`] = `
 <div
   class="action-cell"
 >
-  <div>
-    hello world
-  </div>
+  <span
+    class="bp3-icon bp3-icon-search-template"
+    icon="search-template"
+  >
+    <svg
+      data-icon="search-template"
+      height="16"
+      viewBox="0 0 16 16"
+      width="16"
+    >
+      <desc>
+        search-template
+      </desc>
+      <path
+        d="M15.55 13.43l-2.67-2.67c.7-1.09 1.11-2.38 1.11-3.77 
0-3.87-3.13-7-7-7s-7 3.13-7 7 3.13 7 7 7c1.39 0 2.68-.41 3.77-1.11l2.67 
2.67a1.498 1.498 0 1 0 2.12-2.12zm-8.56-1.44c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 
2.24 5 5-2.24 5-5 5zm2.5-6h-5c-.28 0-.5.22-.5.5s.22.5.5.5h5c.28 0 
.5-.22.5-.5s-.22-.5-.5-.5zm0-2h-5c-.28 0-.5.22-.5.5s.22.5.5.5h5c.28 0 
.5-.22.5-.5s-.22-.5-.5-.5zm0 4h-5c-.28 0-.5.22-.5.5s.22.5.5.5h5c.28 0 
.5-.22.5-.5s-.22-.5-.5-.5z"
+        fill-rule="evenodd"
+      />
+    </svg>
+  </span>
 </div>
 `;
diff --git a/web-console/src/components/action-cell/action-cell.spec.tsx 
b/web-console/src/components/action-cell/action-cell.spec.tsx
index 4683591..94d6471 100644
--- a/web-console/src/components/action-cell/action-cell.spec.tsx
+++ b/web-console/src/components/action-cell/action-cell.spec.tsx
@@ -25,10 +25,10 @@ import { ActionCell} from './action-cell';
 
 describe('describe action cell', () => {
   it('action cell snapshot', () => {
-    const actionCell =
-      <ActionCell >
-        <div>hello world</div>
-      </ActionCell>;
+    const actionCell = <ActionCell
+      onDetail={() => null}
+      actions={[]}
+    />;
     const { container, getByText } = render(actionCell);
     expect(container.firstChild).toMatchSnapshot();
   });
diff --git a/web-console/src/components/action-cell/action-cell.tsx 
b/web-console/src/components/action-cell/action-cell.tsx
index e37b2c9..5252132 100644
--- a/web-console/src/components/action-cell/action-cell.tsx
+++ b/web-console/src/components/action-cell/action-cell.tsx
@@ -16,21 +16,46 @@
  * limitations under the License.
  */
 
+import { Icon, Popover, Position } from '@blueprintjs/core';
+import { IconNames } from '@blueprintjs/icons';
 import * as React from 'react';
 
+import { BasicAction, basicActionsToMenu } from '../../utils/basic-action';
+
 import './action-cell.scss';
 
 export interface ActionCellProps extends React.Props<any> {
+  onDetail?: () => void;
+  actions?: BasicAction[];
 }
 
 export class ActionCell extends React.Component<ActionCellProps, {}> {
+  static COLUMN_ID = 'actions';
+  static COLUMN_LABEL = 'Actions';
+  static COLUMN_WIDTH = 70;
+
   constructor(props: ActionCellProps, context: any) {
     super(props, context);
   }
 
   render() {
+    const { onDetail, actions } = this.props;
+    const actionsMenu = actions ? basicActionsToMenu(actions) : null;
+
     return <div className="action-cell">
-      {this.props.children}
+      {
+        onDetail &&
+        <Icon
+          icon={IconNames.SEARCH_TEMPLATE}
+          onClick={() => onDetail()}
+        />
+      }
+      {
+        actionsMenu &&
+        <Popover content={actionsMenu} position={Position.BOTTOM_RIGHT}>
+          <Icon icon={IconNames.WRENCH}/>
+        </Popover>
+      }
     </div>;
   }
 }
diff --git 
a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap 
b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
index 29b24e3..64769a7 100644
--- 
a/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
+++ 
b/web-console/src/components/header-bar/__snapshots__/header-bar.spec.tsx.snap
@@ -99,7 +99,7 @@ exports[`describe header bar header bar snapshot 1`] = `
       href="#servers"
       icon="database"
       minimal={true}
-      text="Data servers"
+      text="Servers"
     />
     <Blueprint3.NavbarDivider />
     <Blueprint3.AnchorButton
diff --git a/web-console/src/components/header-bar/header-bar.scss 
b/web-console/src/components/header-bar/header-bar.scss
index 77360c7..9ac063c 100644
--- a/web-console/src/components/header-bar/header-bar.scss
+++ b/web-console/src/components/header-bar/header-bar.scss
@@ -16,13 +16,15 @@
  * limitations under the License.
  */
 
+@import "../../variables";
+
 .header-bar {
   overflow: hidden;
 
   .logo {
     position: relative;
     width: 100px;
-    height: 50px;
+    height: $header-bar-height;
 
     svg {
       position: absolute;
diff --git a/web-console/src/components/header-bar/header-bar.tsx 
b/web-console/src/components/header-bar/header-bar.tsx
index be8bbfe..6792db2 100644
--- a/web-console/src/components/header-bar/header-bar.tsx
+++ b/web-console/src/components/header-bar/header-bar.tsx
@@ -163,7 +163,7 @@ export class HeaderBar extends 
React.Component<HeaderBarProps, HeaderBarState> {
         <AnchorButton minimal active={active === 'datasources'} 
icon={IconNames.MULTI_SELECT} text="Datasources" href="#datasources" />
         <AnchorButton minimal active={active === 'segments'} 
icon={IconNames.STACKED_CHART} text="Segments" href="#segments" />
         <AnchorButton minimal active={active === 'tasks'} 
icon={IconNames.GANTT_CHART} text="Tasks" href="#tasks" />
-        <AnchorButton minimal active={active === 'servers'} 
icon={IconNames.DATABASE} text="Data servers" href="#servers" />
+        <AnchorButton minimal active={active === 'servers'} 
icon={IconNames.DATABASE} text="Servers" href="#servers" />
 
         <NavbarDivider/>
         <AnchorButton minimal active={active === 'query'} 
icon={IconNames.APPLICATION} text="Query" href="#query" />
diff --git 
a/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
 
b/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
index 1fb9aa3..033a1b0 100644
--- 
a/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
+++ 
b/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
@@ -5,92 +5,96 @@ exports[`describe sql control sql control snapshot 1`] = `
   class="sql-control"
 >
   <div
-    class=" ace_editor ace-solarized-dark ace_dark ace_focus"
-    id="ace-editor"
-    style="width: 100%; height: 30vh; font-size: 14px;"
+    class="ace-container"
   >
-    <textarea
-      autocapitalize="off"
-      autocorrect="off"
-      class="ace_text-input"
-      spellcheck="false"
-      style="opacity: 0; position: fixed; top: 0px;"
-      wrap="off"
-    />
     <div
-      aria-hidden="true"
-      class="ace_gutter"
+      class=" ace_editor ace-solarized-dark ace_dark ace_focus"
+      id="ace-editor"
+      style="width: 100%; height: 200px; font-size: 14px;"
     >
-      <div
-        class="ace_layer ace_gutter-layer ace_folding-enabled"
+      <textarea
+        autocapitalize="off"
+        autocorrect="off"
+        class="ace_text-input"
+        spellcheck="false"
+        style="opacity: 0; position: fixed; top: 0px;"
+        wrap="off"
       />
       <div
-        class="ace_gutter-active-line"
-      />
-    </div>
-    <div
-      class="ace_scroller"
-    >
+        aria-hidden="true"
+        class="ace_gutter"
+      >
+        <div
+          class="ace_layer ace_gutter-layer ace_folding-enabled"
+        />
+        <div
+          class="ace_gutter-active-line"
+        />
+      </div>
       <div
-        class="ace_content"
+        class="ace_scroller"
       >
         <div
-          class="ace_layer ace_print-margin-layer"
+          class="ace_content"
         >
           <div
-            class="ace_print-margin"
-            style="left: 4px; visibility: hidden;"
+            class="ace_layer ace_print-margin-layer"
+          >
+            <div
+              class="ace_print-margin"
+              style="left: 4px; visibility: hidden;"
+            />
+          </div>
+          <div
+            class="ace_layer ace_marker-layer"
+          />
+          <div
+            class="ace_layer ace_text-layer"
+            style="padding: 0px 4px;"
           />
+          <div
+            class="ace_layer ace_marker-layer"
+          />
+          <div
+            class="ace_layer ace_cursor-layer"
+          >
+            <div
+              class="ace_cursor"
+            />
+          </div>
         </div>
+      </div>
+      <div
+        class="ace_scrollbar ace_scrollbar-v"
+        style="display: none; width: 20px;"
+      >
         <div
-          class="ace_layer ace_marker-layer"
+          class="ace_scrollbar-inner"
+          style="width: 20px;"
         />
+      </div>
+      <div
+        class="ace_scrollbar ace_scrollbar-h"
+        style="display: none; height: 20px;"
+      >
         <div
-          class="ace_layer ace_text-layer"
-          style="padding: 0px 4px;"
+          class="ace_scrollbar-inner"
+          style="height: 20px;"
         />
+      </div>
+      <div
+        style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: hidden;"
+      >
         <div
-          class="ace_layer ace_marker-layer"
+          style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: visible;"
         />
         <div
-          class="ace_layer ace_cursor-layer"
+          style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: visible;"
         >
-          <div
-            class="ace_cursor"
-          />
+          
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
         </div>
       </div>
     </div>
-    <div
-      class="ace_scrollbar ace_scrollbar-v"
-      style="display: none; width: 20px;"
-    >
-      <div
-        class="ace_scrollbar-inner"
-        style="width: 20px;"
-      />
-    </div>
-    <div
-      class="ace_scrollbar ace_scrollbar-h"
-      style="display: none; height: 20px;"
-    >
-      <div
-        class="ace_scrollbar-inner"
-        style="height: 20px;"
-      />
-    </div>
-    <div
-      style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: hidden;"
-    >
-      <div
-        style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: visible;"
-      />
-      <div
-        style="height: auto; width: auto; top: 0px; left: 0px; visibility: 
hidden; position: absolute; white-space: pre; overflow: visible;"
-      >
-        
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-      </div>
-    </div>
   </div>
   <div
     class="buttons"
@@ -163,9 +167,7 @@ exports[`describe sql control sql control snapshot 1`] = `
     <span
       class="query-elapsed"
     >
-       Last query took 
-      0.00
-       seconds
+      Last query took 0.00 seconds
     </span>
   </div>
 </div>
diff --git a/web-console/src/components/sql-control/sql-control.scss 
b/web-console/src/components/sql-control/sql-control.scss
index 2fe4036..694de36 100644
--- a/web-console/src/components/sql-control/sql-control.scss
+++ b/web-console/src/components/sql-control/sql-control.scss
@@ -16,21 +16,31 @@
  * limitations under the License.
  */
 
+@import "../../variables";
 
 .sql-control {
+  .ace-container {
+    position: absolute;
+    width: 100%;
+    top: 0;
+    bottom: 30px + $standard-padding;
 
-  .ace_scroller {
-    background-color: #232C35;
-  }
+    .ace_scroller {
+      background-color: #232C35;
+    }
 
-  .ace_gutter-layer {
-    background-color: #27313c;
+    .ace_gutter-layer {
+      background-color: #27313c;
+    }
   }
 
   .buttons {
-    position: relative;
+    position: absolute;
+    width: 100%;
+    bottom: 0;
+    height: 30px;
 
-    button{
+    button {
       margin-right: 15px;
     }
 
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx 
b/web-console/src/components/sql-control/sql-control.spec.tsx
index 73f7902..8b6bcb4 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/components/sql-control/sql-control.spec.tsx
@@ -21,16 +21,15 @@ import { render } from 'react-testing-library';
 
 import {SqlControl} from './sql-control';
 
-
 describe('describe sql control', () => {
   it('sql control snapshot', () => {
-    const sqlControl =
-      <SqlControl
-        initSql={'test'}
-        onRun={(query: string, bypassCache: boolean, wrapQuery: boolean) => {}}
-        onExplain={(sqlQuery: string) => {}}
-        queryElapsed={2}
-      />
+    const sqlControl = <SqlControl
+      initSql={'test'}
+      onRun={(query, context, wrapQuery) => {}}
+      onExplain={(sqlQuery, context) => {}}
+      queryElapsed={2}
+    />;
+
     const { container, getByText } = render(sqlControl);
     expect(container.firstChild).toMatchSnapshot();
   });
diff --git a/web-console/src/components/sql-control/sql-control.tsx 
b/web-console/src/components/sql-control/sql-control.tsx
index 06f7e80..69d7a00 100644
--- a/web-console/src/components/sql-control/sql-control.tsx
+++ b/web-console/src/components/sql-control/sql-control.tsx
@@ -19,11 +19,11 @@
 import {
   Button,
   ButtonGroup,
-  Intent,
+  Intent, IResizeEntry,
   Menu,
   MenuItem,
   Popover,
-  Position
+  Position, ResizeSensor
 } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
@@ -32,7 +32,6 @@ import 'brace/ext/language_tools';
 import 'brace/mode/hjson';
 import 'brace/mode/sql';
 import 'brace/theme/solarized_dark';
-import * as classNames from 'classnames';
 import * as Hjson from 'hjson';
 import * as React from 'react';
 import AceEditor from 'react-ace';
@@ -46,7 +45,6 @@ import { MenuCheckbox } from 
'./../menu-checkbox/menu-checkbox';
 
 import './sql-control.scss';
 
-
 function validHjson(query: string) {
   try {
     Hjson.parse(query);
@@ -60,8 +58,8 @@ const langTools = ace.acequire('ace/ext/language_tools');
 
 export interface SqlControlProps extends React.Props<any> {
   initSql: string | null;
-  onRun: (query: string, bypassCache: boolean, wrapQuery: boolean) => void;
-  onExplain: (sqlQuery: string) => void;
+  onRun: (query: string, context: Record<string, any>, wrapQuery: boolean) => 
void;
+  onExplain: (sqlQuery: string, context: Record<string, any>) => void;
   queryElapsed: number | null;
 }
 
@@ -69,8 +67,14 @@ export interface SqlControlState {
   query: string;
   autoComplete: boolean;
   autoCompleteLoading: boolean;
-  bypassCache: boolean;
   wrapQuery: boolean;
+  useApproximateCountDistinct: boolean;
+  useApproximateTopN: boolean;
+  useCache: boolean;
+
+  // For reasons (https://github.com/securingsincity/react-ace/issues/415) 
react ace editor needs an explicit height
+  // Since this component will grown and shrink dynamically we will measure 
its height and then set it.
+  editorHeight: number;
 }
 
 export class SqlControl extends React.Component<SqlControlProps, 
SqlControlState> {
@@ -80,8 +84,12 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
       query: props.initSql || '',
       autoComplete: true,
       autoCompleteLoading: false,
-      bypassCache: false,
-      wrapQuery: true
+      wrapQuery: true,
+      useApproximateCountDistinct: true,
+      useApproximateTopN: true,
+      useCache: true,
+
+      editorHeight: 200
     };
   }
 
@@ -209,6 +217,26 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
     this.addCompleters();
   }
 
+  getContext(): Record<string, any> {
+    const { useCache, useApproximateCountDistinct, useApproximateTopN } = 
this.state;
+    const context: Record<string, any> = {};
+
+    if (useCache === false) {
+      context.useCache = false;
+      context.populateCache = false;
+    }
+
+    if (useApproximateCountDistinct === false) {
+      context.useApproximateCountDistinct = false;
+    }
+
+    if (useApproximateTopN === false) {
+      context.useApproximateTopN = false;
+    }
+
+    return context;
+  }
+
   private handleChange = (newValue: string): void => {
     this.setState({
       query: newValue
@@ -217,13 +245,18 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
 
   private onRunClick = () => {
     const { onRun } = this.props;
-    const { query, bypassCache, wrapQuery } = this.state;
-    onRun(query, bypassCache, wrapQuery);
+    const { query, wrapQuery } = this.state;
+    onRun(query, this.getContext(), wrapQuery);
+  }
+
+  private handleAceContainerResize = (entries: IResizeEntry[]) => {
+    if (entries.length !== 1) return;
+    this.setState({ editorHeight: entries[0].contentRect.height });
   }
 
   renderExtraMenu(isRune: boolean) {
     const { onExplain } = this.props;
-    const { query, autoComplete, bypassCache, wrapQuery } = this.state;
+    const { query, autoComplete, useCache, wrapQuery, 
useApproximateCountDistinct, useApproximateTopN } = this.state;
 
     return <Menu>
       <MenuItem
@@ -238,7 +271,7 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
           <MenuItem
             icon={IconNames.CLEAN}
             text="Explain"
-            onClick={() => onExplain(query)}
+            onClick={() => onExplain(query, this.getContext())}
           />
           <MenuCheckbox
             checked={wrapQuery}
@@ -250,45 +283,59 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
             label="Auto complete"
             onChange={() => this.setState({autoComplete: !autoComplete})}
           />
+          <MenuCheckbox
+            checked={useApproximateCountDistinct}
+            label="Use approximate COUNT(DISTINCT)"
+            onChange={() => this.setState({useApproximateCountDistinct: 
!useApproximateCountDistinct})}
+          />
+          <MenuCheckbox
+            checked={useApproximateTopN}
+            label="Use approximate TopN"
+            onChange={() => this.setState({useApproximateTopN: 
!useApproximateTopN})}
+          />
         </>
       }
       <MenuCheckbox
-        checked={bypassCache}
-        label="Bypass cache"
-        onChange={() => this.setState({bypassCache: !bypassCache})}
+        checked={useCache}
+        label="Use cache"
+        onChange={() => this.setState({useCache: !useCache})}
       />
     </Menu>;
   }
 
   render() {
     const { queryElapsed } = this.props;
-    const { query, autoComplete, wrapQuery } = this.state;
+    const { query, autoComplete, wrapQuery, editorHeight } = this.state;
     const isRune = query.trim().startsWith('{');
 
     // Set the key in the AceEditor to force a rebind and prevent an error 
that happens otherwise
     return <div className="sql-control">
-      <AceEditor
-        key={isRune ? 'hjson' : 'sql'}
-        mode={isRune ? 'hjson' : 'sql'}
-        theme="solarized_dark"
-        name="ace-editor"
-        onChange={this.handleChange}
-        focus
-        fontSize={14}
-        width="100%"
-        height="30vh"
-        showPrintMargin={false}
-        value={query}
-        editorProps={{
-          $blockScrolling: Infinity
-        }}
-        setOptions={{
-          enableBasicAutocompletion: isRune ? false : autoComplete,
-          enableLiveAutocompletion: isRune ? false : autoComplete,
-          showLineNumbers: true,
-          tabSize: 2
-        }}
-      />
+      <ResizeSensor onResize={this.handleAceContainerResize}>
+        <div className="ace-container">
+          <AceEditor
+            key={isRune ? 'hjson' : 'sql'}
+            mode={isRune ? 'hjson' : 'sql'}
+            theme="solarized_dark"
+            name="ace-editor"
+            onChange={this.handleChange}
+            focus
+            fontSize={14}
+            width="100%"
+            height={`${editorHeight}px`}
+            showPrintMargin={false}
+            value={query}
+            editorProps={{
+              $blockScrolling: Infinity
+            }}
+            setOptions={{
+              enableBasicAutocompletion: isRune ? false : autoComplete,
+              enableLiveAutocompletion: isRune ? false : autoComplete,
+              showLineNumbers: true,
+              tabSize: 2
+            }}
+          />
+        </div>
+      </ResizeSensor>
       <div className="buttons">
         <ButtonGroup>
           <Button
@@ -303,7 +350,9 @@ export class SqlControl extends 
React.Component<SqlControlProps, SqlControlState
         </ButtonGroup>
         {
           queryElapsed &&
-          <span className="query-elapsed"> Last query took {(queryElapsed / 
1000).toFixed(2)} seconds</span>
+          <span className="query-elapsed">
+            {`Last query took ${(queryElapsed / 1000).toFixed(2)} seconds`}
+          </span>
         }
       </div>
     </div>;
diff --git a/web-console/src/components/view-control-bar/view-control-bar.scss 
b/web-console/src/components/view-control-bar/view-control-bar.scss
index 40cb7f2..5b7aa89 100644
--- a/web-console/src/components/view-control-bar/view-control-bar.scss
+++ b/web-console/src/components/view-control-bar/view-control-bar.scss
@@ -16,8 +16,10 @@
  * limitations under the License.
  */
 
+@import "../../variables";
+
 .view-control-bar {
-  height: 30px;
+  height: $view-control-bar-height;
   white-space: nowrap;
 
   & > * {
diff --git a/web-console/src/console-application.scss 
b/web-console/src/console-application.scss
index 0c702e6..c17a48b 100644
--- a/web-console/src/console-application.scss
+++ b/web-console/src/console-application.scss
@@ -25,7 +25,7 @@
 
   .view-container {
     position: absolute;
-    top: 50px;
+    top: $header-bar-height;
     left: 0;
     right: 0;
     bottom: 0;
diff --git a/web-console/src/entry.scss b/web-console/src/entry.scss
index ed31ec4..fcea2e2 100644
--- a/web-console/src/entry.scss
+++ b/web-console/src/entry.scss
@@ -72,3 +72,5 @@ svg {
     }
   }
 }
+
+// Some SplitterLayout globals
diff --git a/web-console/src/utils/general.tsx 
b/web-console/src/utils/general.tsx
index 87d5e24..64ec28c 100644
--- a/web-console/src/utils/general.tsx
+++ b/web-console/src/utils/general.tsx
@@ -122,11 +122,15 @@ export function countBy<T>(array: T[], fn: (x: T, index: 
number) => string = Str
   return counts;
 }
 
-export function lookupBy<T>(array: T[], fn: (x: T, index: number) => string = 
String): Record<string, T> {
-  const lookup: Record<string, T> = {};
+function identity(x: any): any {
+  return x;
+}
+
+export function lookupBy<T, Q>(array: T[], keyFn: (x: T, index: number) => 
string = String, valueFn: (x: T, index: number) => Q = identity): 
Record<string, Q> {
+  const lookup: Record<string, Q> = {};
   for (let i = 0; i < array.length; i++) {
-    const key = fn(array[i], i);
-    lookup[key] = array[i];
+    const a = array[i];
+    lookup[keyFn(a, i)] = valueFn(a, i);
   }
   return lookup;
 }
diff --git a/web-console/src/utils/ingestion-spec.tsx 
b/web-console/src/utils/ingestion-spec.tsx
index 8c83f67..355dc39 100644
--- a/web-console/src/utils/ingestion-spec.tsx
+++ b/web-console/src/utils/ingestion-spec.tsx
@@ -841,51 +841,50 @@ export function 
getIoConfigTuningFormFields(ingestionComboType: IngestionComboTy
     case 'index:http':
     case 'index:static-s3':
     case 'index:static-google-blobstore':
-      const objectType = ingestionComboType === 'index:http' ? 'http' : 'S3';
       return [
         {
-          name: 'firehose.maxCacheCapacityBytes',
-          label: 'Max cache capacity bytes',
+          name: 'firehose.fetchTimeout',
+          label: 'Fetch timeout',
           type: 'number',
-          defaultValue: 1073741824,
+          defaultValue: 60000,
           info: <>
-            <p>Maximum size of the cache space in bytes. 0 means disabling 
cache. Cached files are not removed until the ingestion task completes.</p>
+            <p>Timeout for fetching the object.</p>
           </>
         },
         {
-          name: 'firehose.maxFetchCapacityBytes',
-          label: 'Max fetch capacity bytes',
+          name: 'firehose.maxFetchRetry',
+          label: 'Max fetch retry',
           type: 'number',
-          defaultValue: 1073741824,
+          defaultValue: 3,
           info: <>
-            <p>Maximum size of the fetch space in bytes. 0 means disabling 
prefetch. Prefetched files are removed immediately once they are read.</p>
+            <p>Maximum retry for fetching the object.</p>
           </>
         },
         {
-          name: 'firehose.prefetchTriggerBytes',
-          label: 'Prefetch trigger bytes',
+          name: 'firehose.maxCacheCapacityBytes',
+          label: 'Max cache capacity bytes',
           type: 'number',
+          defaultValue: 1073741824,
           info: <>
-            <p>Threshold to trigger prefetching {objectType} objects.</p>
-            <p>Default: maxFetchCapacityBytes / 2</p>
+            <p>Maximum size of the cache space in bytes. 0 means disabling 
cache. Cached files are not removed until the ingestion task completes.</p>
           </>
         },
         {
-          name: 'firehose.fetchTimeout',
-          label: 'Fetch timeout',
+          name: 'firehose.maxFetchCapacityBytes',
+          label: 'Max fetch capacity bytes',
           type: 'number',
-          defaultValue: 60000,
+          defaultValue: 1073741824,
           info: <>
-            <p>Timeout for fetching a http object.</p>
+            <p>Maximum size of the fetch space in bytes. 0 means disabling 
prefetch. Prefetched files are removed immediately once they are read.</p>
           </>
         },
         {
-          name: 'firehose.maxFetchRetry',
-          label: 'Max fetch retry',
+          name: 'firehose.prefetchTriggerBytes',
+          label: 'Prefetch trigger bytes',
           type: 'number',
-          defaultValue: 3,
+          placeholder: 'maxFetchCapacityBytes / 2',
           info: <>
-            <p>Maximum retry for fetching a {objectType} object.</p>
+            <p>Threshold to trigger prefetching the objects.</p>
           </>
         }
       ];
diff --git a/web-console/src/utils/local-storage-keys.tsx 
b/web-console/src/utils/local-storage-keys.tsx
index 50bbd51..7ed711a 100644
--- a/web-console/src/utils/local-storage-keys.tsx
+++ b/web-console/src/utils/local-storage-keys.tsx
@@ -23,12 +23,10 @@ export const LocalStorageKeys = {
   SUPERVISOR_TABLE_COLUMN_SELECTION: 'supervisor-table-column-selection' as 
'supervisor-table-column-selection',
   TASK_TABLE_COLUMN_SELECTION: 'task-table-column-selection' as 
'task-table-column-selection',
   SERVER_TABLE_COLUMN_SELECTION: 'historical-table-column-selection' as 
'historical-table-column-selection',
-  MIDDLEMANAGER_TABLE_COLUMN_SELECTION: 'middleManager-table-column-selection' 
as 'middleManager-table-column-selection',
   LOOKUP_TABLE_COLUMN_SELECTION: 'lookup-table-column-selection' as 
'lookup-table-column-selection',
   QUERY_KEY: 'druid-console-query' as 'druid-console-query',
   TASKS_VIEW_PANE_SIZE: 'tasks-view-pane-size' as 'tasks-view-pane-size',
-  SERVERS_VIEW_PANE_SIZE: 'servers-view-pane-size' as 'servers-view-pane-size'
-
+  QUERY_VIEW_PANE_SIZE: 'query-view-pane-size' as 'query-view-pane-size'
 };
 export type LocalStorageKeys = typeof LocalStorageKeys[keyof typeof 
LocalStorageKeys];
 
diff --git a/web-console/src/variables.scss b/web-console/src/variables.scss
index 6a867c8..ef3c770 100644
--- a/web-console/src/variables.scss
+++ b/web-console/src/variables.scss
@@ -16,4 +16,6 @@
  * limitations under the License.
  */
 
+$header-bar-height: 50px;
+$view-control-bar-height: 30px;
 $standard-padding: 15px;
diff --git 
a/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
 
b/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
index edd0a39..516c111 100644
--- 
a/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
+++ 
b/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
@@ -57,7 +57,7 @@ exports[`describe data source view data source view snapshot 
1`] = `
     TrComponent={[Function]}
     TrGroupComponent={[Function]}
     aggregatedKey="_aggregated"
-    className="-striped -highlight"
+    className=""
     collapseOnDataChange={true}
     collapseOnPageChange={true}
     collapseOnSortingChange={true}
diff --git a/web-console/src/views/datasource-view/datasource-view.scss 
b/web-console/src/views/datasource-view/datasource-view.scss
index b552485..62878d6 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/views/datasource-view/datasource-view.scss
@@ -16,6 +16,8 @@
  * limitations under the License.
  */
 
+@import "../../variables";
+
 .data-sources-view {
   height: 100%;
   width: 100%;
@@ -26,7 +28,7 @@
 
   .ReactTable {
     position: absolute;
-    top: 50px;
+    top: $view-control-bar-height + $standard-padding;
     bottom: 0;
     width: 100%;
   }
diff --git a/web-console/src/views/datasource-view/datasource-view.tsx 
b/web-console/src/views/datasource-view/datasource-view.tsx
index 674d421..35d46f9 100644
--- a/web-console/src/views/datasource-view/datasource-view.tsx
+++ b/web-console/src/views/datasource-view/datasource-view.tsx
@@ -22,8 +22,8 @@ import axios from 'axios';
 import * as React from 'react';
 import ReactTable, { Filter } from 'react-table';
 
-import { ActionCell, RuleEditor, TableColumnSelection, ViewControlBar} from 
'../../components/index';
-import { AsyncActionDialog, CompactionDialog, RetentionDialog } from 
'../../dialogs/index';
+import { ActionCell, RuleEditor, TableColumnSelection, ViewControlBar} from 
'../../components';
+import { AsyncActionDialog, CompactionDialog, RetentionDialog } from 
'../../dialogs';
 import { AppToaster } from '../../singletons/toaster';
 import {
   addFilter,
@@ -36,12 +36,12 @@ import {
   queryDruidSql,
   QueryManager, TableColumnSelectionHandler
 } from '../../utils';
-import { BasicAction, basicActionsToMenu } from '../../utils/basic-action';
+import { BasicAction } from '../../utils/basic-action';
 
 import './datasource-view.scss';
 
-const tableColumns: string[] = ['Datasource', 'Availability', 'Retention', 
'Compaction', 'Size', 'Num rows', 'Actions'];
-const tableColumnsNoSql: string[] = ['Datasource', 'Availability', 
'Retention', 'Compaction', 'Size', 'Actions'];
+const tableColumns: string[] = ['Datasource', 'Availability', 'Retention', 
'Compaction', 'Size', 'Num rows', ActionCell.COLUMN_LABEL];
+const tableColumnsNoSql: string[] = ['Datasource', 'Availability', 
'Retention', 'Compaction', 'Size', ActionCell.COLUMN_LABEL];
 
 export interface DatasourcesViewProps extends React.Props<any> {
   goToSql: (initSql: string) => void;
@@ -609,31 +609,21 @@ GROUP BY 1`);
             show: !noSqlMode && tableColumnSelectionHandler.showColumn('Num 
rows')
           },
           {
-            Header: 'Actions',
+            Header: ActionCell.COLUMN_LABEL,
             accessor: 'datasource',
-            id: 'actions',
-            width: 70,
+            id: ActionCell.COLUMN_ID,
+            width: ActionCell.COLUMN_WIDTH,
             filterable: false,
             Cell: row => {
               const datasource = row.value;
               const { disabled } = row.original;
               const datasourceActions = this.getDatasourceActions(datasource, 
disabled);
-              const datasourceMenu = basicActionsToMenu(datasourceActions);
-
-              return <ActionCell>
-                {
-                  datasourceMenu &&
-                  <Popover content={datasourceMenu} 
position={Position.BOTTOM_RIGHT}>
-                    <Icon icon={IconNames.WRENCH}/>
-                  </Popover>
-                }
-              </ActionCell>;
+              return <ActionCell actions={datasourceActions}/>;
             },
-            show: tableColumnSelectionHandler.showColumn('Actions')
+            show: 
tableColumnSelectionHandler.showColumn(ActionCell.COLUMN_LABEL)
           }
         ]}
         defaultPageSize={50}
-        className="-striped -highlight"
       />
       {this.renderDropDataAction()}
       {this.renderEnableAction()}
diff --git 
a/web-console/src/views/home-view/__snapshots__/home-view.spec.tsx.snap 
b/web-console/src/views/home-view/__snapshots__/home-view.spec.tsx.snap
index 68a390f..b62f0f4 100644
--- a/web-console/src/views/home-view/__snapshots__/home-view.spec.tsx.snap
+++ b/web-console/src/views/home-view/__snapshots__/home-view.spec.tsx.snap
@@ -124,7 +124,7 @@ exports[`describe home view home viexw snapshot 1`] = `
           icon="database"
         />
          
-        Data servers
+        Servers
       </Component>
       <p>
         Loading...
diff --git a/web-console/src/views/home-view/home-view.tsx 
b/web-console/src/views/home-view/home-view.tsx
index 61c0540..ff113c3 100644
--- a/web-console/src/views/home-view/home-view.tsx
+++ b/web-console/src/views/home-view/home-view.tsx
@@ -22,7 +22,7 @@ import axios from 'axios';
 import * as React from 'react';
 
 import { UrlBaser } from '../../singletons/url-baser';
-import { getHeadProp, pluralIfNeeded, queryDruidSql, QueryManager } from 
'../../utils';
+import { getHeadProp, lookupBy, pluralIfNeeded, queryDruidSql, QueryManager } 
from '../../utils';
 
 import './home-view.scss';
 
@@ -65,13 +65,15 @@ export interface HomeViewState {
   waitingTaskCount: number;
   taskCountError: string | null;
 
-  dataServerCountLoading: boolean;
-  dataServerCount: number;
-  dataServerCountError: string | null;
-
-  middleManagerCountLoading: boolean;
+  serverCountLoading: boolean;
+  coordinatorCount: number;
+  overlordCount: number;
+  routerCount: number;
+  brokerCount: number;
+  historicalCount: number;
   middleManagerCount: number;
-  middleManagerCountError: string | null;
+  peonCount: number;
+  serverCountError: string | null;
 }
 
 export class HomeView extends React.Component<HomeViewProps, HomeViewState> {
@@ -80,8 +82,7 @@ export class HomeView extends React.Component<HomeViewProps, 
HomeViewState> {
   private segmentQueryManager: QueryManager<string, any>;
   private supervisorQueryManager: QueryManager<string, any>;
   private taskQueryManager: QueryManager<string, any>;
-  private dataServerQueryManager: QueryManager<string, any>;
-  private middleManagerQueryManager: QueryManager<string, any>;
+  private serverQueryManager: QueryManager<string, any>;
 
   constructor(props: HomeViewProps, context: any) {
     super(props, context);
@@ -111,13 +112,15 @@ export class HomeView extends 
React.Component<HomeViewProps, HomeViewState> {
       waitingTaskCount: 0,
       taskCountError: null,
 
-      dataServerCountLoading: false,
-      dataServerCount: 0,
-      dataServerCountError: null,
-
-      middleManagerCountLoading: false,
+      serverCountLoading: false,
+      coordinatorCount: 0,
+      overlordCount: 0,
+      routerCount: 0,
+      brokerCount: 0,
+      historicalCount: 0,
       middleManagerCount: 0,
-      middleManagerCountError: null
+      peonCount: 0,
+      serverCountError: null
     };
   }
 
@@ -168,11 +171,7 @@ export class HomeView extends 
React.Component<HomeViewProps, HomeViewState> {
 
     this.segmentQueryManager = new QueryManager({
       processQuery: async (query) => {
-        if (!noSqlMode) {
-          const segments = await queryDruidSql({ query });
-          return getHeadProp(segments, 'count') || 0;
-        } else {
-
+        if (noSqlMode) {
           const loadstatusResp = await 
axios.get('/druid/coordinator/v1/loadstatus?simple');
           const loadstatus = loadstatusResp.data;
           const unavailableSegmentNum = Object.keys(loadstatus).reduce((sum, 
key) => {
@@ -186,8 +185,12 @@ export class HomeView extends 
React.Component<HomeViewProps, HomeViewState> {
           }, 0);
 
           return availableSegmentNum + unavailableSegmentNum;
-        }
 
+        } else {
+          const segments = await queryDruidSql({ query });
+          return getHeadProp(segments, 'count') || 0;
+
+        }
       },
       onStateChange: ({ result, loading, error }) => {
         this.setState({
@@ -228,37 +231,33 @@ export class HomeView extends 
React.Component<HomeViewProps, HomeViewState> {
 
     this.taskQueryManager = new QueryManager({
       processQuery: async (query) => {
-        let taskCountsFromQuery: {status: string, count: number}[] = [];
-        if (!noSqlMode) {
-          taskCountsFromQuery = await queryDruidSql({ query });
-        } else {
+        if (noSqlMode) {
           const completeTasksResp = await 
axios.get('/druid/indexer/v1/completeTasks');
           const runningTasksResp = await 
axios.get('/druid/indexer/v1/runningTasks');
-          const waitingTasksResp = await 
axios.get('/druid/indexer/v1/waitingTasks');
           const pendingTasksResp = await 
axios.get('/druid/indexer/v1/pendingTasks');
-          taskCountsFromQuery.push(
-            {status: 'SUCCESS', count: completeTasksResp.data.filter((d: any) 
=> d.status === 'SUCCESS').length},
-            {status: 'FAILED', count: completeTasksResp.data.filter((d: any) 
=> d.status === 'FAILED').length},
-            {status: 'RUNNING', count: runningTasksResp.data.length},
-            {status: 'WAITING', count: waitingTasksResp.data.length},
-            {status: 'PENDING', count: pendingTasksResp.data.length}
-          );
+          const waitingTasksResp = await 
axios.get('/druid/indexer/v1/waitingTasks');
+          return {
+            SUCCESS: completeTasksResp.data.filter((d: any) => d.status === 
'SUCCESS').length,
+            FAILED: completeTasksResp.data.filter((d: any) => d.status === 
'FAILED').length,
+            RUNNING: runningTasksResp.data.length,
+            PENDING: pendingTasksResp.data.length,
+            WAITING: waitingTasksResp.data.length
+          };
+
+        } else {
+          const taskCountsFromQuery: { status: string, count: number }[] = 
await queryDruidSql({ query });
+          return lookupBy(taskCountsFromQuery, x => x.status, x => x.count);
+
         }
-        const taskCounts = taskCountsFromQuery.reduce((acc: any, curr: any) => 
{
-          const status = curr.status.toLowerCase();
-          const property = `${status}TaskCount`;
-          return {...acc, [property]: curr.count};
-        }, {});
-        return taskCounts;
       },
       onStateChange: ({ result, loading, error }) => {
         this.setState({
           taskCountLoading: loading,
-          successTaskCount: result ? result.successTaskCount : 0,
-          failedTaskCount: result ? result.failedTaskCount : 0,
-          runningTaskCount: result ? result.runningTaskCount : 0,
-          pendingTaskCount: result ? result.pendingTaskCount : 0,
-          waitingTaskCount: result ? result.waitingTaskCount : 0,
+          successTaskCount: result ? result.SUCCESS : 0,
+          failedTaskCount: result ? result.FAILED : 0,
+          runningTaskCount: result ? result.RUNNING : 0,
+          pendingTaskCount: result ? result.PENDING : 0,
+          waitingTaskCount: result ? result.WAITING : 0,
           taskCountError: error
         });
       }
@@ -272,60 +271,48 @@ GROUP BY 1`);
 
     // -------------------------
 
-    this.dataServerQueryManager = new QueryManager({
+    this.serverQueryManager = new QueryManager({
       processQuery: async (query) => {
-        const getDataServerNum = async () => {
-          const allServerResp = await 
axios.get('/druid/coordinator/v1/servers?simple');
-          const allServers = allServerResp.data;
-          return allServers.filter((s: any) => s.type === 'historical').length;
-        };
-        if (!noSqlMode) {
-          const dataServerCounts = await queryDruidSql({ query });
-          const serverNum = getHeadProp(dataServerCounts, 'count') || 0;
-          if (serverNum === 0) return await getDataServerNum();
-          return serverNum;
-        } else {
-          return await getDataServerNum();
-        }
-      },
-      onStateChange: ({ result, loading, error }) => {
-        this.setState({
-          dataServerCountLoading: loading,
-          dataServerCount: result,
-          dataServerCountError: error
-        });
-      }
-    });
+        if (noSqlMode) {
+          const serversResp = await 
axios.get('/druid/coordinator/v1/servers?simple');
+          const middleManagerResp = await 
axios.get('/druid/indexer/v1/workers');
+          return {
+            historical: serversResp.data.filter((s: any) => s.type === 
'historical').length,
+            middle_manager: middleManagerResp.data.length,
+            peon: serversResp.data.filter((s: any) => s.type === 
'indexer-executor').length
+          };
 
-    this.dataServerQueryManager.runQuery(`SELECT COUNT(*) as "count" FROM 
sys.servers WHERE "server_type" = 'historical'`);
-
-    // -------------------------
+        } else {
+          const serverCountsFromQuery: { server_type: string, count: number 
}[] = await queryDruidSql({ query });
+          return lookupBy(serverCountsFromQuery, x => x.server_type, x => 
x.count);
 
-    this.middleManagerQueryManager = new QueryManager({
-      processQuery: async (query) => {
-        const middleManagerResp = await axios.get('/druid/indexer/v1/workers');
-        const middleManagerCount: number = middleManagerResp.data.length;
-        return middleManagerCount;
+        }
       },
       onStateChange: ({ result, loading, error }) => {
         this.setState({
-          middleManagerCountLoading: loading,
-          middleManagerCount: result,
-          middleManagerCountError: error
+          serverCountLoading: loading,
+          coordinatorCount: result ? result.coordinator : 0,
+          overlordCount: result ? result.overlord : 0,
+          routerCount: result ? result.router : 0,
+          brokerCount: result ? result.broker : 0,
+          historicalCount: result ? result.historical : 0,
+          middleManagerCount: result ? result.middle_manager : 0,
+          peonCount: result ? result.peon : 0,
+          serverCountError: error
         });
       }
     });
 
-    this.middleManagerQueryManager.runQuery(`dummy`);
+    this.serverQueryManager.runQuery(`SELECT server_type, COUNT(*) as "count" 
FROM sys.servers GROUP BY 1`);
   }
 
   componentWillUnmount(): void {
     this.statusQueryManager.terminate();
     this.datasourceQueryManager.terminate();
     this.segmentQueryManager.terminate();
+    this.supervisorQueryManager.terminate();
     this.taskQueryManager.terminate();
-    this.dataServerQueryManager.terminate();
-    this.middleManagerQueryManager.terminate();
+    this.serverQueryManager.terminate();
   }
 
   renderCard(cardOptions: CardOptions): JSX.Element {
@@ -341,76 +328,94 @@ GROUP BY 1`);
     const state = this.state;
 
     return <div className="home-view app-view">
-      {this.renderCard({
-        href: UrlBaser.base('/status'),
-        icon: IconNames.GRAPH,
-        title: 'Status',
-        loading: state.statusLoading,
-        content: state.status ? `Apache Druid is running version 
${state.status.version}` : '',
-        error: state.statusError
-      })}
-
-      {this.renderCard({
-        href: '#datasources',
-        icon: IconNames.MULTI_SELECT,
-        title: 'Datasources',
-        loading: state.datasourceCountLoading,
-        content: pluralIfNeeded(state.datasourceCount, 'datasource'),
-        error: state.datasourceCountError
-      })}
-
-      {this.renderCard({
-        href: '#segments',
-        icon: IconNames.STACKED_CHART,
-        title: 'Segments',
-        loading: state.segmentCountLoading,
-        content: pluralIfNeeded(state.segmentCount, 'segment'),
-        error: state.datasourceCountError
-      })}
-
-      {this.renderCard({
-        href: '#tasks',
-        icon: IconNames.LIST_COLUMNS,
-        title: 'Supervisors',
-        loading: state.supervisorCountLoading,
-        content: <>
+      {
+        this.renderCard({
+          href: UrlBaser.base('/status'),
+          icon: IconNames.GRAPH,
+          title: 'Status',
+          loading: state.statusLoading,
+          content: state.status ? `Apache Druid is running version 
${state.status.version}` : '',
+          error: state.statusError
+        })
+      }
+      {
+        this.renderCard({
+          href: '#datasources',
+          icon: IconNames.MULTI_SELECT,
+          title: 'Datasources',
+          loading: state.datasourceCountLoading,
+          content: pluralIfNeeded(state.datasourceCount, 'datasource'),
+          error: state.datasourceCountError
+        })
+      }
+      {
+        this.renderCard({
+          href: '#segments',
+          icon: IconNames.STACKED_CHART,
+          title: 'Segments',
+          loading: state.segmentCountLoading,
+          content: pluralIfNeeded(state.segmentCount, 'segment'),
+          error: state.datasourceCountError
+        })
+      }
+      {
+        this.renderCard({
+          href: '#tasks',
+          icon: IconNames.LIST_COLUMNS,
+          title: 'Supervisors',
+          loading: state.supervisorCountLoading,
+          content: <>
             {!Boolean(state.runningSupervisorCount + 
state.suspendedSupervisorCount) && <p>0 supervisors</p>}
             {Boolean(state.runningSupervisorCount) && 
<p>{pluralIfNeeded(state.runningSupervisorCount, 'running supervisor')}</p>}
             {Boolean(state.suspendedSupervisorCount) && 
<p>{pluralIfNeeded(state.suspendedSupervisorCount, 'suspended supervisor')}</p>}
           </>,
-        error: state.supervisorCountError
-      })}
-
-      {this.renderCard({
-        href: '#tasks',
-        icon: IconNames.GANTT_CHART,
-        title: 'Tasks',
-        loading: state.taskCountLoading,
-        content: <>
-          {Boolean(state.runningTaskCount) && 
<p>{pluralIfNeeded(state.runningTaskCount, 'running task')}</p>}
-          {Boolean(state.pendingTaskCount) && 
<p>{pluralIfNeeded(state.pendingTaskCount, 'pending task')}</p>}
-          {Boolean(state.successTaskCount) && 
<p>{pluralIfNeeded(state.successTaskCount, 'successful task')}</p>}
-          {Boolean(state.waitingTaskCount) && 
<p>{pluralIfNeeded(state.waitingTaskCount, 'waiting task')}</p>}
-          {Boolean(state.failedTaskCount) && 
<p>{pluralIfNeeded(state.failedTaskCount, 'failed task')}</p>}
-          {!(Boolean(state.runningTaskCount) || 
Boolean(state.pendingTaskCount) || Boolean(state.successTaskCount) ||
-            Boolean(state.waitingTaskCount) || Boolean(state.failedTaskCount)) 
&&
-            <p>There are no tasks</p>
-          }
+          error: state.supervisorCountError
+        })
+      }
+      {
+        this.renderCard({
+          href: '#tasks',
+          icon: IconNames.GANTT_CHART,
+          title: 'Tasks',
+          loading: state.taskCountLoading,
+          content: <>
+            {Boolean(state.runningTaskCount) && 
<p>{pluralIfNeeded(state.runningTaskCount, 'running task')}</p>}
+            {Boolean(state.pendingTaskCount) && 
<p>{pluralIfNeeded(state.pendingTaskCount, 'pending task')}</p>}
+            {Boolean(state.successTaskCount) && 
<p>{pluralIfNeeded(state.successTaskCount, 'successful task')}</p>}
+            {Boolean(state.waitingTaskCount) && 
<p>{pluralIfNeeded(state.waitingTaskCount, 'waiting task')}</p>}
+            {Boolean(state.failedTaskCount) && 
<p>{pluralIfNeeded(state.failedTaskCount, 'failed task')}</p>}
+            {
+              !(
+                Boolean(state.runningTaskCount) ||
+                Boolean(state.pendingTaskCount) ||
+                Boolean(state.successTaskCount) ||
+                Boolean(state.waitingTaskCount) ||
+                Boolean(state.failedTaskCount)
+              ) &&
+              <p>There are no tasks</p>
+            }
           </>,
-        error: state.taskCountError
-      })}
-
-      {this.renderCard({
-        href: '#servers',
-        icon: IconNames.DATABASE,
-        title: 'Data servers',
-        loading: state.dataServerCountLoading || 
state.middleManagerCountLoading,
-        content: <>
-          <p>{pluralIfNeeded(state.dataServerCount, 'historical')}</p>
-          <p>{pluralIfNeeded(state.middleManagerCount, 'middlemanager')}</p>
-        </>,
-        error: state.dataServerCountError
-      })}
+          error: state.taskCountError
+        })
+      }
+      {
+        this.renderCard({
+          href: '#servers',
+          icon: IconNames.DATABASE,
+          title: 'Servers',
+          loading: state.serverCountLoading,
+          content: <>
+            <p>{`${pluralIfNeeded(state.overlordCount, 'overlord')}, 
${pluralIfNeeded(state.coordinatorCount, 'coordinator')}`}</p>
+            <p>{`${pluralIfNeeded(state.routerCount, 'router')}, 
${pluralIfNeeded(state.brokerCount, 'broker')}`}</p>
+            <p>{`${pluralIfNeeded(state.historicalCount, 'historical')}, 
${pluralIfNeeded(state.middleManagerCount, 'middle manager')}`}</p>
+            {
+              Boolean(state.peonCount) &&
+              <p>{pluralIfNeeded(state.peonCount, 'peon')}</p>
+            }
+          </>,
+          error: state.serverCountError
+        })
+      }
     </div>;
   }
 }
diff --git a/web-console/src/views/load-data-view/load-data-view.tsx 
b/web-console/src/views/load-data-view/load-data-view.tsx
index fdba39c..61bddda 100644
--- a/web-console/src/views/load-data-view/load-data-view.tsx
+++ b/web-console/src/views/load-data-view/load-data-view.tsx
@@ -31,8 +31,8 @@ import * as classNames from 'classnames';
 import * as React from 'react';
 import ReactTable from 'react-table';
 
-import { AutoForm, CenterMessage, ClearableInput, ExternalLink, JSONInput, 
Loader, NullTableCell } from '../../components/index';
-import { AsyncActionDialog } from '../../dialogs/index';
+import { AutoForm, CenterMessage, ClearableInput, ExternalLink, JSONInput, 
Loader, NullTableCell } from '../../components';
+import { AsyncActionDialog } from '../../dialogs';
 import { AppToaster } from '../../singletons/toaster';
 import {
   filterMap,
@@ -782,7 +782,6 @@ export class LoadDataView extends 
React.Component<LoadDataViewProps, LoadDataVie
           defaultPageSize={50}
           showPagination={false}
           sortable={false}
-          className="-striped -highlight"
         />
       </div>;
     }
@@ -1062,7 +1061,6 @@ export class LoadDataView extends 
React.Component<LoadDataViewProps, LoadDataVie
           defaultPageSize={50}
           showPagination={false}
           sortable={false}
-          className="-striped -highlight"
         />
       </div>;
     }
@@ -1255,7 +1253,6 @@ export class LoadDataView extends 
React.Component<LoadDataViewProps, LoadDataVie
           defaultPageSize={50}
           showPagination={false}
           sortable={false}
-          className="-striped -highlight"
         />
       </div>;
     }
@@ -1493,7 +1490,6 @@ export class LoadDataView extends 
React.Component<LoadDataViewProps, LoadDataVie
           defaultPageSize={50}
           showPagination={false}
           sortable={false}
-          className="-striped -highlight"
         />
       </div>;
     }
@@ -1815,7 +1811,6 @@ export class LoadDataView extends 
React.Component<LoadDataViewProps, LoadDataVie
           defaultPageSize={50}
           showPagination={false}
           sortable={false}
-          className="-striped -highlight"
         />
       </div>;
     }
diff --git 
a/web-console/src/views/lookups-view/__snapshots__/lookups-view.spec.tsx.snap 
b/web-console/src/views/lookups-view/__snapshots__/lookups-view.spec.tsx.snap
index 148a732..2ef65d6 100644
--- 
a/web-console/src/views/lookups-view/__snapshots__/lookups-view.spec.tsx.snap
+++ 
b/web-console/src/views/lookups-view/__snapshots__/lookups-view.spec.tsx.snap
@@ -50,7 +50,7 @@ exports[`describe lookups view lookups view snapshot 1`] = `
     TrComponent={[Function]}
     TrGroupComponent={[Function]}
     aggregatedKey="_aggregated"
-    className="-striped -highlight"
+    className=""
     collapseOnDataChange={true}
     collapseOnPageChange={true}
     collapseOnSortingChange={true}
diff --git a/web-console/src/views/lookups-view/lookups-view.tsx 
b/web-console/src/views/lookups-view/lookups-view.tsx
index d72d189..4c1b0a1 100644
--- a/web-console/src/views/lookups-view/lookups-view.tsx
+++ b/web-console/src/views/lookups-view/lookups-view.tsx
@@ -36,7 +36,7 @@ import {BasicAction, basicActionsToMenu} from 
'../../utils/basic-action';
 import './lookups-view.scss';
 
 
-const tableColumns: string[] = ['Lookup name', 'Tier', 'Type', 'Version', 
'Actions'];
+const tableColumns: string[] = ['Lookup name', 'Tier', 'Type', 'Version', 
ActionCell.COLUMN_LABEL];
 
 const DEFAULT_LOOKUP_TIER: string = '__default';
 
@@ -214,7 +214,7 @@ export class LookupsView extends 
React.Component<LookupsViewProps, LookupsViewSt
     }
   }
 
-  private getlookupActions(lookupTier: string, lookupId: string): 
BasicAction[] {
+  private getLookupActions(lookupTier: string, lookupId: string): 
BasicAction[] {
     return [
       {
         icon: IconNames.EDIT,
@@ -304,31 +304,21 @@ export class LookupsView extends 
React.Component<LookupsViewProps, LookupsViewSt
             show: tableColumnSelectionHandler.showColumn('Version')
           },
           {
-            Header: 'Actions',
-            id: 'actions',
-            width: 70,
+            Header: ActionCell.COLUMN_LABEL,
+            id: ActionCell.COLUMN_ID,
+            width: ActionCell.COLUMN_WIDTH,
             accessor: row => ({id: row.id, tier: row.tier}),
             filterable: false,
             Cell: (row: any) => {
               const lookupId = row.value.id;
               const lookupTier = row.value.tier;
-              const lookupActions = this.getlookupActions(lookupTier, 
lookupId);
-              const lookupMenu = basicActionsToMenu(lookupActions);
-
-              return <ActionCell>
-                {
-                  lookupMenu &&
-                  <Popover content={lookupMenu} 
position={Position.BOTTOM_RIGHT}>
-                      <Icon icon={IconNames.WRENCH}/>
-                  </Popover>
-                }
-              </ActionCell>;
+              const lookupActions = this.getLookupActions(lookupTier, 
lookupId);
+              return <ActionCell actions={lookupActions}/>;
             },
-            show: tableColumnSelectionHandler.showColumn('Actions')
+            show: 
tableColumnSelectionHandler.showColumn(ActionCell.COLUMN_LABEL)
           }
         ]}
         defaultPageSize={50}
-        className="-striped -highlight"
       />
     </>;
   }
diff --git 
a/web-console/src/views/segments-view/__snapshots__/segments-view.spec.tsx.snap 
b/web-console/src/views/segments-view/__snapshots__/segments-view.spec.tsx.snap
index ee2f486..ec973f4 100644
--- 
a/web-console/src/views/segments-view/__snapshots__/segments-view.spec.tsx.snap
+++ 
b/web-console/src/views/segments-view/__snapshots__/segments-view.spec.tsx.snap
@@ -60,7 +60,7 @@ exports[`describe segments-view segments view snapshot 1`] = `
     TrComponent={[Function]}
     TrGroupComponent={[Function]}
     aggregatedKey="_aggregated"
-    className="-striped -highlight"
+    className=""
     collapseOnDataChange={true}
     collapseOnPageChange={true}
     collapseOnSortingChange={true}
diff --git a/web-console/src/views/segments-view/segments-view.scss 
b/web-console/src/views/segments-view/segments-view.scss
index 31816a4..aa7c1f4 100644
--- a/web-console/src/views/segments-view/segments-view.scss
+++ b/web-console/src/views/segments-view/segments-view.scss
@@ -16,13 +16,15 @@
  * limitations under the License.
  */
 
+@import "../../variables";
+
 .segments-view {
   height: 100%;
   width: 100%;
 
   .ReactTable {
     position: absolute;
-    top: 50px;
+    top: $view-control-bar-height + $standard-padding;
     bottom: 0;
     width: 100%;
 
diff --git a/web-console/src/views/segments-view/segments-view.tsx 
b/web-console/src/views/segments-view/segments-view.tsx
index 0cae93b..9c53d7f 100644
--- a/web-console/src/views/segments-view/segments-view.tsx
+++ b/web-console/src/views/segments-view/segments-view.tsx
@@ -24,7 +24,7 @@ import * as React from 'react';
 import ReactTable from 'react-table';
 import { Filter } from 'react-table';
 
-import { TableColumnSelection, ViewControlBar } from '../../components/index';
+import { TableColumnSelection, ViewControlBar } from '../../components';
 import {
   addFilter,
   formatBytes,
@@ -363,7 +363,6 @@ export class SegmentsView extends 
React.Component<SegmentsViewProps, SegmentsVie
         }
       ]}
       defaultPageSize={50}
-      className="-striped -highlight"
       SubComponent={rowInfo => {
         const { original } = rowInfo;
         const { payload } = rowInfo.original;
diff --git 
a/web-console/src/views/servers-view/__snapshots__/servers-view.spec.tsx.snap 
b/web-console/src/views/servers-view/__snapshots__/servers-view.spec.tsx.snap
index 3741b8c..dee904d 100644
--- 
a/web-console/src/views/servers-view/__snapshots__/servers-view.spec.tsx.snap
+++ 
b/web-console/src/views/servers-view/__snapshots__/servers-view.spec.tsx.snap
@@ -1,507 +1,308 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`describe servers view action servers view 1`] = `
-<t
-  customClassName="servers-view app-view"
-  onDragEnd={null}
-  onDragStart={null}
-  onSecondaryPaneSizeChange={[Function]}
-  percentage={true}
-  primaryIndex={0}
-  primaryMinSize={30}
-  secondaryInitialSize={60}
-  secondaryMinSize={30}
-  vertical={true}
+<div
+  className="servers-view app-view"
 >
-  <div
-    className="top-pane"
+  <ViewControlBar
+    label="Servers"
   >
-    <ViewControlBar
-      label="Historicals"
-    >
+    <Component>
+      Group by
+    </Component>
+    <Blueprint3.ButtonGroup>
       <Blueprint3.Button
-        icon="refresh"
+        active={true}
         onClick={[Function]}
-        text="Refresh"
-      />
+      >
+        None
+      </Blueprint3.Button>
       <Blueprint3.Button
-        icon="application"
+        active={false}
         onClick={[Function]}
-        text="Go to SQL"
-      />
-      <Blueprint3.Switch
-        checked={false}
-        label="Group by tier"
-        onChange={[Function]}
-      />
-      <TableColumnSelection
-        columns={
-          Array [
-            "Server",
-            "Tier",
-            "Curr size",
-            "Max size",
-            "Usage",
-            "Load/drop queues",
-            "Host",
-            "Port",
-          ]
-        }
-        onChange={[Function]}
-        tableColumnsHidden={Array []}
-      />
-    </ViewControlBar>
-    <ReactTable
-      AggregatedComponent={[Function]}
-      ExpanderComponent={[Function]}
-      FilterComponent={[Function]}
-      LoadingComponent={[Function]}
-      NoDataComponent={[Function]}
-      PadRowComponent={[Function]}
-      PaginationComponent={[Function]}
-      PivotValueComponent={[Function]}
-      ResizerComponent={[Function]}
-      TableComponent={[Function]}
-      TbodyComponent={[Function]}
-      TdComponent={[Function]}
-      TfootComponent={[Function]}
-      ThComponent={[Function]}
-      TheadComponent={[Function]}
-      TrComponent={[Function]}
-      TrGroupComponent={[Function]}
-      aggregatedKey="_aggregated"
-      className="-striped -highlight"
-      collapseOnDataChange={true}
-      collapseOnPageChange={true}
-      collapseOnSortingChange={true}
-      column={
-        Object {
-          "Aggregated": undefined,
-          "Cell": undefined,
-          "Expander": undefined,
-          "Filter": undefined,
-          "Footer": undefined,
-          "Header": undefined,
-          "Pivot": undefined,
-          "PivotValue": undefined,
-          "aggregate": undefined,
-          "className": "",
-          "filterAll": false,
-          "filterMethod": undefined,
-          "filterable": undefined,
-          "footerClassName": "",
-          "footerStyle": Object {},
-          "getFooterProps": [Function],
-          "getHeaderProps": [Function],
-          "getProps": [Function],
-          "headerClassName": "",
-          "headerStyle": Object {},
-          "minWidth": 100,
-          "resizable": undefined,
-          "show": true,
-          "sortMethod": undefined,
-          "sortable": undefined,
-          "style": Object {},
-        }
-      }
+      >
+        Type
+      </Blueprint3.Button>
+      <Blueprint3.Button
+        active={false}
+        onClick={[Function]}
+      >
+        Tier
+      </Blueprint3.Button>
+    </Blueprint3.ButtonGroup>
+    <Blueprint3.Button
+      icon="refresh"
+      onClick={[Function]}
+      text="Refresh"
+    />
+    <Blueprint3.Button
+      icon="application"
+      onClick={[Function]}
+      text="Go to SQL"
+    />
+    <TableColumnSelection
       columns={
         Array [
-          Object {
-            "Aggregated": [Function],
-            "Header": "Server",
-            "accessor": "server",
-            "show": true,
-            "width": 300,
-          },
-          Object {
-            "Cell": [Function],
-            "Header": "Tier",
-            "accessor": "tier",
-            "show": true,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Cell": [Function],
-            "Header": "Curr size",
-            "accessor": "curr_size",
-            "filterable": false,
-            "id": "curr_size",
-            "show": true,
-            "width": 100,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Cell": [Function],
-            "Header": "Max size",
-            "accessor": "max_size",
-            "filterable": false,
-            "id": "max_size",
-            "show": true,
-            "width": 100,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Cell": [Function],
-            "Header": "Usage",
-            "accessor": [Function],
-            "filterable": false,
-            "id": "usage",
-            "show": true,
-            "width": 100,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Cell": [Function],
-            "Header": "Load/drop queues",
-            "accessor": [Function],
-            "filterable": false,
-            "id": "queue",
-            "show": true,
-            "width": 400,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Header": "Host",
-            "accessor": "host",
-            "show": true,
-          },
-          Object {
-            "Aggregated": [Function],
-            "Header": "Port",
-            "accessor": [Function],
-            "id": "port",
-            "show": true,
-          },
+          "Server",
+          "Type",
+          "Tier",
+          "Host",
+          "Port",
+          "Curr size",
+          "Max size",
+          "Usage",
+          "Detail",
+          "Actions",
         ]
       }
-      data={Array []}
-      defaultExpanded={Object {}}
-      defaultFilterMethod={[Function]}
-      defaultFiltered={Array []}
-      defaultPageSize={10}
-      defaultResized={Array []}
-      defaultSortDesc={false}
-      defaultSortMethod={[Function]}
-      defaultSorted={Array []}
-      expanderDefaults={
+      onChange={[Function]}
+      tableColumnsHidden={Array []}
+    />
+  </ViewControlBar>
+  <ReactTable
+    AggregatedComponent={[Function]}
+    ExpanderComponent={[Function]}
+    FilterComponent={[Function]}
+    LoadingComponent={[Function]}
+    NoDataComponent={[Function]}
+    PadRowComponent={[Function]}
+    PaginationComponent={[Function]}
+    PivotValueComponent={[Function]}
+    ResizerComponent={[Function]}
+    TableComponent={[Function]}
+    TbodyComponent={[Function]}
+    TdComponent={[Function]}
+    TfootComponent={[Function]}
+    ThComponent={[Function]}
+    TheadComponent={[Function]}
+    TrComponent={[Function]}
+    TrGroupComponent={[Function]}
+    aggregatedKey="_aggregated"
+    className=""
+    collapseOnDataChange={true}
+    collapseOnPageChange={true}
+    collapseOnSortingChange={true}
+    column={
+      Object {
+        "Aggregated": undefined,
+        "Cell": undefined,
+        "Expander": undefined,
+        "Filter": undefined,
+        "Footer": undefined,
+        "Header": undefined,
+        "Pivot": undefined,
+        "PivotValue": undefined,
+        "aggregate": undefined,
+        "className": "",
+        "filterAll": false,
+        "filterMethod": undefined,
+        "filterable": undefined,
+        "footerClassName": "",
+        "footerStyle": Object {},
+        "getFooterProps": [Function],
+        "getHeaderProps": [Function],
+        "getProps": [Function],
+        "headerClassName": "",
+        "headerStyle": Object {},
+        "minWidth": 100,
+        "resizable": undefined,
+        "show": true,
+        "sortMethod": undefined,
+        "sortable": undefined,
+        "style": Object {},
+      }
+    }
+    columns={
+      Array [
+        Object {
+          "Aggregated": [Function],
+          "Header": "Server",
+          "accessor": "server",
+          "show": true,
+          "width": 300,
+        },
+        Object {
+          "Cell": [Function],
+          "Header": "Type",
+          "accessor": "server_type",
+          "show": true,
+          "width": 150,
+        },
         Object {
+          "Cell": [Function],
+          "Header": "Tier",
+          "accessor": "tier",
+          "show": true,
+        },
+        Object {
+          "Aggregated": [Function],
+          "Header": "Host",
+          "accessor": "host",
+          "show": true,
+        },
+        Object {
+          "Aggregated": [Function],
+          "Header": "Port",
+          "accessor": [Function],
+          "id": "port",
+          "show": true,
+        },
+        Object {
+          "Aggregated": [Function],
+          "Cell": [Function],
+          "Header": "Curr size",
+          "accessor": "curr_size",
           "filterable": false,
-          "resizable": false,
-          "sortable": false,
-          "width": 35,
-        }
-      }
-      filterable={true}
-      filtered={Array []}
-      freezeWhenExpanded={false}
-      getLoadingProps={[Function]}
-      getNoDataProps={[Function]}
-      getPaginationProps={[Function]}
-      getProps={[Function]}
-      getResizerProps={[Function]}
-      getTableProps={[Function]}
-      getTbodyProps={[Function]}
-      getTdProps={[Function]}
-      getTfootProps={[Function]}
-      getTfootTdProps={[Function]}
-      getTfootTrProps={[Function]}
-      getTheadFilterProps={[Function]}
-      getTheadFilterThProps={[Function]}
-      getTheadFilterTrProps={[Function]}
-      getTheadGroupProps={[Function]}
-      getTheadGroupThProps={[Function]}
-      getTheadGroupTrProps={[Function]}
-      getTheadProps={[Function]}
-      getTheadThProps={[Function]}
-      getTheadTrProps={[Function]}
-      getTrGroupProps={[Function]}
-      getTrProps={[Function]}
-      groupedByPivotKey="_groupedByPivot"
-      indexKey="_index"
-      loading={true}
-      loadingText="Loading..."
-      multiSort={true}
-      nestingLevelKey="_nestingLevel"
-      nextText="Next"
-      noDataText=""
-      ofText="of"
-      onFetchData={[Function]}
-      onFilteredChange={[Function]}
-      originalKey="_original"
-      pageSizeOptions={
-        Array [
-          5,
-          10,
-          20,
-          25,
-          50,
-          100,
-        ]
-      }
-      pageText="Page"
-      pivotBy={Array []}
-      pivotDefaults={Object {}}
-      pivotIDKey="_pivotID"
-      pivotValKey="_pivotVal"
-      previousText="Previous"
-      resizable={true}
-      resolveData={[Function]}
-      rowsText="rows"
-      showPageJump={true}
-      showPageSizeOptions={true}
-      showPagination={true}
-      showPaginationBottom={true}
-      showPaginationTop={false}
-      sortable={true}
-      style={Object {}}
-      subRowsKey="_subRows"
-    />
-  </div>
-  <div
-    className="bottom-pane"
-  >
-    <ViewControlBar
-      label="MiddleManagers"
-    >
-      <Blueprint3.Button
-        icon="refresh"
-        onClick={[Function]}
-        text="Refresh"
-      />
-      <TableColumnSelection
-        columns={
-          Array [
-            "Host",
-            "Usage",
-            "Availability groups",
-            "Last completed task time",
-            "Blacklisted until",
-            "Status",
-            "Actions",
-          ]
-        }
-        onChange={[Function]}
-        tableColumnsHidden={Array []}
-      />
-    </ViewControlBar>
-    <ReactTable
-      AggregatedComponent={[Function]}
-      ExpanderComponent={[Function]}
-      FilterComponent={[Function]}
-      LoadingComponent={[Function]}
-      NoDataComponent={[Function]}
-      PadRowComponent={[Function]}
-      PaginationComponent={[Function]}
-      PivotValueComponent={[Function]}
-      ResizerComponent={[Function]}
-      SubComponent={[Function]}
-      TableComponent={[Function]}
-      TbodyComponent={[Function]}
-      TdComponent={[Function]}
-      TfootComponent={[Function]}
-      ThComponent={[Function]}
-      TheadComponent={[Function]}
-      TrComponent={[Function]}
-      TrGroupComponent={[Function]}
-      aggregatedKey="_aggregated"
-      className="-striped -highlight"
-      collapseOnDataChange={true}
-      collapseOnPageChange={true}
-      collapseOnSortingChange={true}
-      column={
+          "id": "curr_size",
+          "show": true,
+          "width": 100,
+        },
         Object {
-          "Aggregated": undefined,
-          "Cell": undefined,
-          "Expander": undefined,
-          "Filter": undefined,
-          "Footer": undefined,
-          "Header": undefined,
-          "Pivot": undefined,
-          "PivotValue": undefined,
-          "aggregate": undefined,
-          "className": "",
-          "filterAll": false,
-          "filterMethod": undefined,
-          "filterable": undefined,
-          "footerClassName": "",
-          "footerStyle": Object {},
-          "getFooterProps": [Function],
-          "getHeaderProps": [Function],
-          "getProps": [Function],
-          "headerClassName": "",
-          "headerStyle": Object {},
-          "minWidth": 100,
-          "resizable": undefined,
+          "Aggregated": [Function],
+          "Cell": [Function],
+          "Header": "Max size",
+          "accessor": "max_size",
+          "filterable": false,
+          "id": "max_size",
           "show": true,
-          "sortMethod": undefined,
-          "sortable": undefined,
-          "style": Object {},
-        }
-      }
-      columns={
-        Array [
-          Object {
-            "Cell": [Function],
-            "Header": "Host",
-            "accessor": [Function],
-            "id": "host",
-            "show": true,
-          },
-          Object {
-            "Header": "Usage",
-            "accessor": [Function],
-            "filterable": false,
-            "id": "usage",
-            "show": true,
-            "width": 60,
-          },
-          Object {
-            "Header": "Availability groups",
-            "accessor": [Function],
-            "filterable": false,
-            "id": "availabilityGroups",
-            "show": true,
-            "width": 60,
-          },
-          Object {
-            "Header": "Last completed task time",
-            "accessor": "lastCompletedTaskTime",
-            "show": true,
-          },
-          Object {
-            "Header": "Blacklisted until",
-            "accessor": "blacklistedUntil",
-            "show": true,
-          },
-          Object {
-            "Header": "Status",
-            "accessor": [Function],
-            "id": "status",
-            "show": true,
-          },
-          Object {
-            "Cell": [Function],
-            "Header": "Actions",
-            "accessor": [Function],
-            "filterable": false,
-            "id": "actions",
-            "show": true,
-            "width": 70,
-          },
-        ]
-      }
-      data={Array []}
-      defaultExpanded={Object {}}
-      defaultFilterMethod={[Function]}
-      defaultFiltered={Array []}
-      defaultPageSize={10}
-      defaultResized={Array []}
-      defaultSortDesc={false}
-      defaultSortMethod={[Function]}
-      defaultSorted={Array []}
-      expanderDefaults={
+          "width": 100,
+        },
         Object {
+          "Aggregated": [Function],
+          "Cell": [Function],
+          "Header": "Usage",
+          "accessor": [Function],
           "filterable": false,
-          "resizable": false,
-          "sortable": false,
-          "width": 35,
-        }
-      }
-      filterable={true}
-      filtered={
-        Array [
-          Object {
-            "id": "host",
-            "value": "test",
-          },
-        ]
-      }
-      freezeWhenExpanded={false}
-      getLoadingProps={[Function]}
-      getNoDataProps={[Function]}
-      getPaginationProps={[Function]}
-      getProps={[Function]}
-      getResizerProps={[Function]}
-      getTableProps={[Function]}
-      getTbodyProps={[Function]}
-      getTdProps={[Function]}
-      getTfootProps={[Function]}
-      getTfootTdProps={[Function]}
-      getTfootTrProps={[Function]}
-      getTheadFilterProps={[Function]}
-      getTheadFilterThProps={[Function]}
-      getTheadFilterTrProps={[Function]}
-      getTheadGroupProps={[Function]}
-      getTheadGroupThProps={[Function]}
-      getTheadGroupTrProps={[Function]}
-      getTheadProps={[Function]}
-      getTheadThProps={[Function]}
-      getTheadTrProps={[Function]}
-      getTrGroupProps={[Function]}
-      getTrProps={[Function]}
-      groupedByPivotKey="_groupedByPivot"
-      indexKey="_index"
-      loading={true}
-      loadingText="Loading..."
-      multiSort={true}
-      nestingLevelKey="_nestingLevel"
-      nextText="Next"
-      noDataText=""
-      ofText="of"
-      onFetchData={[Function]}
-      onFilteredChange={[Function]}
-      originalKey="_original"
-      pageSizeOptions={
-        Array [
-          5,
-          10,
-          20,
-          25,
-          50,
-          100,
-        ]
+          "id": "usage",
+          "show": true,
+          "width": 100,
+        },
+        Object {
+          "Aggregated": [Function],
+          "Cell": [Function],
+          "Header": "Detail",
+          "accessor": [Function],
+          "filterable": false,
+          "id": "queue",
+          "show": true,
+          "width": 400,
+        },
+        Object {
+          "Cell": [Function],
+          "Header": "Actions",
+          "accessor": [Function],
+          "filterable": false,
+          "id": "actions",
+          "show": true,
+          "width": 70,
+        },
+      ]
+    }
+    data={Array []}
+    defaultExpanded={Object {}}
+    defaultFilterMethod={[Function]}
+    defaultFiltered={Array []}
+    defaultPageSize={50}
+    defaultResized={Array []}
+    defaultSortDesc={false}
+    defaultSortMethod={[Function]}
+    defaultSorted={Array []}
+    expanderDefaults={
+      Object {
+        "filterable": false,
+        "resizable": false,
+        "sortable": false,
+        "width": 35,
       }
-      pageText="Page"
-      pivotDefaults={Object {}}
-      pivotIDKey="_pivotID"
-      pivotValKey="_pivotVal"
-      previousText="Previous"
-      resizable={true}
-      resolveData={[Function]}
-      rowsText="rows"
-      showPageJump={true}
-      showPageSizeOptions={true}
-      showPagination={true}
-      showPaginationBottom={true}
-      showPaginationTop={false}
-      sortable={true}
-      style={Object {}}
-      subRowsKey="_subRows"
-    />
-    <AsyncActionDialog
-      action={null}
-      confirmButtonText="Disable worker"
-      failText="Could not disable worker"
-      intent="danger"
-      onClose={[Function]}
-      successText="Worker has been disabled"
-    >
-      <p>
-        Are you sure you want to disable worker 'null'?
-      </p>
-    </AsyncActionDialog>
-    <AsyncActionDialog
-      action={null}
-      confirmButtonText="Enable worker"
-      failText="Could not enable worker"
-      intent="primary"
-      onClose={[Function]}
-      successText="Worker has been enabled"
-    >
-      <p>
-        Are you sure you want to enable worker 'null'?
-      </p>
-    </AsyncActionDialog>
-  </div>
-</t>
+    }
+    filterable={true}
+    filtered={Array []}
+    freezeWhenExpanded={false}
+    getLoadingProps={[Function]}
+    getNoDataProps={[Function]}
+    getPaginationProps={[Function]}
+    getProps={[Function]}
+    getResizerProps={[Function]}
+    getTableProps={[Function]}
+    getTbodyProps={[Function]}
+    getTdProps={[Function]}
+    getTfootProps={[Function]}
+    getTfootTdProps={[Function]}
+    getTfootTrProps={[Function]}
+    getTheadFilterProps={[Function]}
+    getTheadFilterThProps={[Function]}
+    getTheadFilterTrProps={[Function]}
+    getTheadGroupProps={[Function]}
+    getTheadGroupThProps={[Function]}
+    getTheadGroupTrProps={[Function]}
+    getTheadProps={[Function]}
+    getTheadThProps={[Function]}
+    getTheadTrProps={[Function]}
+    getTrGroupProps={[Function]}
+    getTrProps={[Function]}
+    groupedByPivotKey="_groupedByPivot"
+    indexKey="_index"
+    loading={true}
+    loadingText="Loading..."
+    multiSort={true}
+    nestingLevelKey="_nestingLevel"
+    nextText="Next"
+    noDataText=""
+    ofText="of"
+    onFetchData={[Function]}
+    onFilteredChange={[Function]}
+    originalKey="_original"
+    pageSizeOptions={
+      Array [
+        5,
+        10,
+        20,
+        25,
+        50,
+        100,
+      ]
+    }
+    pageText="Page"
+    pivotBy={Array []}
+    pivotDefaults={Object {}}
+    pivotIDKey="_pivotID"
+    pivotValKey="_pivotVal"
+    previousText="Previous"
+    resizable={true}
+    resolveData={[Function]}
+    rowsText="rows"
+    showPageJump={true}
+    showPageSizeOptions={true}
+    showPagination={true}
+    showPaginationBottom={true}
+    showPaginationTop={false}
+    sortable={true}
+    style={Object {}}
+    subRowsKey="_subRows"
+  />
+  <AsyncActionDialog
+    action={null}
+    confirmButtonText="Disable worker"
+    failText="Could not disable worker"
+    intent="danger"
+    onClose={[Function]}
+    successText="Worker has been disabled"
+  >
+    <p>
+      Are you sure you want to disable worker 'null'?
+    </p>
+  </AsyncActionDialog>
+  <AsyncActionDialog
+    action={null}
+    confirmButtonText="Enable worker"
+    failText="Could not enable worker"
+    intent="primary"
+    onClose={[Function]}
+    successText="Worker has been enabled"
+  >
+    <p>
+      Are you sure you want to enable worker 'null'?
+    </p>
+  </AsyncActionDialog>
+</div>
 `;
diff --git a/web-console/src/views/servers-view/servers-view.scss 
b/web-console/src/views/servers-view/servers-view.scss
index 9029e82..c7834f7 100644
--- a/web-console/src/views/servers-view/servers-view.scss
+++ b/web-console/src/views/servers-view/servers-view.scss
@@ -22,29 +22,17 @@
   height: 100%;
   width: 100%;
 
-  .view-control-bar{
+  .view-control-bar {
     margin-bottom: $standard-padding;
   }
 
-  .splitter-layout.splitter-layout-vertical > .layout-splitter{
-    height: 2px;
-    background-color: #6d8ea9;
-    padding-top: 5px;
-  }
-
   .ReactTable{
     position: absolute;
-    top: 50px;
+    top: $view-control-bar-height + $standard-padding;
     bottom: 0;
     width: 100%;
   }
 
-  .bottom-pane {
-    height: 100%;
-    position: relative;
-    padding-top: 15px;
-  }
-
   ul {
     line-height: 20px;
   }
@@ -52,7 +40,7 @@
   .fill-indicator {
     position: relative;
     width: 100%;
-    height: 100%;
+    height: 16px;
     background-color: #dadada;
     border-radius: 2px;
 
diff --git a/web-console/src/views/servers-view/servers-view.tsx 
b/web-console/src/views/servers-view/servers-view.tsx
index 5dc78ae..3d9446e 100644
--- a/web-console/src/views/servers-view/servers-view.tsx
+++ b/web-console/src/views/servers-view/servers-view.tsx
@@ -16,12 +16,11 @@
  * limitations under the License.
  */
 
-import { Button, Icon, Intent, Popover, Position, Switch } from 
'@blueprintjs/core';
+import { Button, ButtonGroup, Intent, Label } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
 import { sum } from 'd3-array';
 import * as React from 'react';
-import SplitterLayout from 'react-splitter-layout';
 import ReactTable from 'react-table';
 import { Filter } from 'react-table';
 
@@ -29,21 +28,21 @@ import {
   ActionCell,
   TableColumnSelection,
   ViewControlBar
-} from '../../components/index';
-import { AsyncActionDialog } from '../../dialogs/index';
+} from '../../components';
+import { AsyncActionDialog } from '../../dialogs';
 import {
   addFilter,
   formatBytes,
-  formatBytesCompact, localStorageGet, LocalStorageKeys, localStorageSet,
+  formatBytesCompact, LocalStorageKeys, lookupBy,
   queryDruidSql,
   QueryManager, TableColumnSelectionHandler
 } from '../../utils';
-import { BasicAction, basicActionsToMenu } from '../../utils/basic-action';
+import { BasicAction } from '../../utils/basic-action';
+import { deepGet } from '../../utils/object-change';
 
 import './servers-view.scss';
 
-const serverTableColumns: string[] = ['Server', 'Tier', 'Curr size', 'Max 
size', 'Usage', 'Load/drop queues', 'Host', 'Port'];
-const middleManagerTableColumns: string[] = ['Host', 'Usage', 'Availability 
groups', 'Last completed task time', 'Blacklisted until', 'Status', 'Actions'];
+const serverTableColumns: string[] = ['Server', 'Type', 'Tier', 'Host', 
'Port', 'Curr size', 'Max size', 'Usage', 'Detail', ActionCell.COLUMN_LABEL];
 
 function formatQueues(segmentsToLoad: number, segmentsToLoadSize: number, 
segmentsToDrop: number, segmentsToDropSize: number): string {
   const queueParts: string[] = [];
@@ -53,7 +52,7 @@ function formatQueues(segmentsToLoad: number, 
segmentsToLoadSize: number, segmen
   if (segmentsToDrop) {
     queueParts.push(`${segmentsToDrop} segments to drop 
(${formatBytesCompact(segmentsToDropSize)})`);
   }
-  return queueParts.join(', ') || 'Empty queues';
+  return queueParts.join(', ') || 'Empty load/drop queues';
 }
 
 export interface ServersViewProps extends React.Props<any> {
@@ -68,29 +67,28 @@ export interface ServersViewState {
   servers: any[] | null;
   serversError: string | null;
   serverFilter: Filter[];
-  groupByTier: boolean;
-
-  middleManagersLoading: boolean;
-  middleManagers: any[] | null;
-  middleManagersError: string | null;
-  middleManagerFilter: Filter[];
+  groupServersBy: null | 'server_type' | 'tier';
 
   middleManagerDisableWorkerHost: string | null;
   middleManagerEnableWorkerHost: string | null;
 }
 
 interface ServerQueryResultRow {
+  server: string;
+  server_type: string;
+  tier: string;
   curr_size: number;
   host: string;
   max_size: number;
   plaintext_port: number;
-  server: string;
-  tier: string;
   tls_port: number;
-  segmentsToDrop?: number;
-  segmentsToDropSize?: number;
-  segmentsToLoad?: number;
-  segmentsToLoadSize?: number;
+}
+
+interface LoadQueueStatus {
+  segmentsToDrop: number;
+  segmentsToDropSize: number;
+  segmentsToLoad: number;
+  segmentsToLoadSize: number;
 }
 
 interface MiddleManagerQueryResultRow {
@@ -99,14 +97,20 @@ interface MiddleManagerQueryResultRow {
   currCapacityUsed: number;
   lastCompletedTaskTime: string;
   runningTasks: string[];
-  worker: any;
+  worker: {
+    capacity: number;
+    host: string;
+    ip: string;
+    scheme: string;
+    version: string;
+  };
 }
 
+interface ServerResultRow extends ServerQueryResultRow, 
Partial<LoadQueueStatus>, Partial<MiddleManagerQueryResultRow> {}
+
 export class ServersView extends React.Component<ServersViewProps, 
ServersViewState> {
   private serverQueryManager: QueryManager<string, ServerQueryResultRow[]>;
-  private middleManagerQueryManager: QueryManager<string, 
MiddleManagerQueryResultRow[]>;
   private serverTableColumnSelectionHandler: TableColumnSelectionHandler;
-  private middleManagerTableColumnSelectionHandler: 
TableColumnSelectionHandler;
 
   constructor(props: ServersViewProps, context: any) {
     super(props, context);
@@ -115,12 +119,7 @@ export class ServersView extends 
React.Component<ServersViewProps, ServersViewSt
       servers: null,
       serversError: null,
       serverFilter: [],
-      groupByTier: false,
-
-      middleManagersLoading: true,
-      middleManagers: null,
-      middleManagersError: null,
-      middleManagerFilter: props.middleManager ? [{ id: 'host', value: 
props.middleManager }] : [],
+      groupServersBy: null,
 
       middleManagerDisableWorkerHost: null,
       middleManagerEnableWorkerHost: null
@@ -129,26 +128,20 @@ export class ServersView extends 
React.Component<ServersViewProps, ServersViewSt
     this.serverTableColumnSelectionHandler = new TableColumnSelectionHandler(
       LocalStorageKeys.SERVER_TABLE_COLUMN_SELECTION, () => this.setState({})
     );
-
-    this.middleManagerTableColumnSelectionHandler = new 
TableColumnSelectionHandler(
-      LocalStorageKeys.MIDDLEMANAGER_TABLE_COLUMN_SELECTION, () => 
this.setState({})
-    );
-    if (!localStorageGet(LocalStorageKeys.SERVERS_VIEW_PANE_SIZE)) {
-      localStorageSet(LocalStorageKeys.SERVERS_VIEW_PANE_SIZE, '60');
-    }
   }
 
-  static getServers = async (): Promise<ServerQueryResultRow[]> => {
+  static async getServers(): Promise<ServerQueryResultRow[]> {
     const allServerResp = await 
axios.get('/druid/coordinator/v1/servers?simple');
     const allServers = allServerResp.data;
-    return allServers.filter((s: any) => s.type === 'historical').map((s: any) 
=> {
+    return allServers.map((s: any) => {
       return {
+        server: s.host,
+        server_type: s.type === 'indexer-executor' ? 'peon' : s.type,
+        tier: s.tier,
         host: s.host.split(':')[0],
         plaintext_port: parseInt(s.host.split(':')[1], 10),
-        server: s.host,
         curr_size: s.currSize,
         max_size: s.maxSize,
-        tier: s.tier,
         tls_port: -1
       };
     });
@@ -161,21 +154,47 @@ export class ServersView extends 
React.Component<ServersViewProps, ServersViewSt
         let servers: ServerQueryResultRow[];
         if (!noSqlMode) {
           servers = await queryDruidSql({ query });
-          if (servers.length === 0) {
-            servers = await ServersView.getServers();
-          }
         } else {
           servers = await ServersView.getServers();
         }
+
         const loadQueueResponse = await 
axios.get('/druid/coordinator/v1/loadqueue?simple');
-        const loadQueues = loadQueueResponse.data;
-        return servers.map((s: any) => {
+        const loadQueues: Record<string, LoadQueueStatus> = 
loadQueueResponse.data;
+        servers = servers.map((s: any) => {
           const loadQueueInfo = loadQueues[s.server];
           if (loadQueueInfo) {
             s = Object.assign(s, loadQueueInfo);
           }
           return s;
         });
+
+        let middleManagers: MiddleManagerQueryResultRow[];
+        try {
+          const middleManagerResponse = await 
axios.get('/druid/indexer/v1/workers');
+          middleManagers = middleManagerResponse.data;
+        } catch (e) {
+          if (
+            e.response &&
+            typeof e.response.data === 'object' &&
+            e.response.data.error === 'Task Runner does not support worker 
listing'
+          ) {
+            // Swallow this error because it simply a reflection of a local 
task runner.
+            middleManagers = [];
+          } else {
+            // Otherwise re-throw.
+            throw e;
+          }
+        }
+
+        const middleManagersLookup = lookupBy(middleManagers, (m) => 
m.worker.host);
+
+        return servers.map((s: any) => {
+          const middleManagerInfo = middleManagersLookup[s.server];
+          if (middleManagerInfo) {
+            s = Object.assign(s, middleManagerInfo);
+          }
+          return s;
+        });
       },
       onStateChange: ({ result, loading, error }) => {
         this.setState({
@@ -186,46 +205,48 @@ export class ServersView extends 
React.Component<ServersViewProps, ServersViewSt
       }
     });
 
+    // Ranking
+    //   coordinator => 7
+    //   overlord => 6
+    //   router => 5
+    //   broker => 4
+    //   historical => 3
+    //   middle_manager => 2
+    //   peon => 1
+
     this.serverQueryManager.runQuery(`SELECT
-  "tier", "server", "host", "plaintext_port", "tls_port", "curr_size", 
"max_size"
+  "server", "server_type", "tier", "host", "plaintext_port", "tls_port", 
"curr_size", "max_size",
+  (
+    CASE "server_type"
+    WHEN 'coordinator' THEN 7
+    WHEN 'overlord' THEN 6
+    WHEN 'router' THEN 5
+    WHEN 'broker' THEN 4
+    WHEN 'historical' THEN 3
+    WHEN 'middle_manager' THEN 2
+    WHEN 'peon' THEN 1
+    ELSE 0
+    END
+  ) AS "rank"
 FROM sys.servers
-WHERE "server_type" = 'historical'`);
-
-    this.middleManagerQueryManager = new QueryManager({
-      processQuery: async (query: string) => {
-        const resp = await axios.get('/druid/indexer/v1/workers');
-        return resp.data;
-      },
-      onStateChange: ({ result, loading, error }) => {
-        this.setState({
-          middleManagers: result,
-          middleManagersLoading: loading,
-          middleManagersError: error
-        });
-      }
-    });
-
-    this.middleManagerQueryManager.runQuery('dummy');
+ORDER BY "rank" DESC, "server" DESC`);
 
   }
 
   componentWillUnmount(): void {
     this.serverQueryManager.terminate();
-    this.middleManagerQueryManager.terminate();
-  }
-
-  private onSecondaryPaneSizeChange(secondaryPaneSize: number) {
-    localStorageSet(LocalStorageKeys.SERVERS_VIEW_PANE_SIZE, 
String(secondaryPaneSize));
   }
 
   renderServersTable() {
-    const { servers, serversLoading, serversError, serverFilter, groupByTier } 
= this.state;
+    const { servers, serversLoading, serversError, serverFilter, 
groupServersBy } = this.state;
     const { serverTableColumnSelectionHandler } = this;
 
     const fillIndicator = (value: number) => {
+      let formattedValue = (value * 100).toFixed(1);
+      if (formattedValue === '0.0' && value > 0) formattedValue = '~' + 
formattedValue;
       return <div className="fill-indicator">
         <div className="bar" style={{ width: `${value * 100}%` }}/>
-        <div className="label">{(value * 100).toFixed(1) + '%'}</div>
+        <div className="label">{formattedValue + '%'}</div>
       </div>;
     };
 
@@ -238,7 +259,8 @@ WHERE "server_type" = 'historical'`);
       onFilteredChange={(filtered, column) => {
         this.setState({ serverFilter: filtered });
       }}
-      pivotBy={groupByTier ? ['tier'] : []}
+      pivotBy={groupServersBy ? [groupServersBy] : []}
+      defaultPageSize={50}
       columns={[
         {
           Header: 'Server',
@@ -248,6 +270,16 @@ WHERE "server_type" = 'historical'`);
           show: serverTableColumnSelectionHandler.showColumn('Server')
         },
         {
+          Header: 'Type',
+          accessor: 'server_type',
+          width: 150,
+          Cell: row => {
+            const value = row.value;
+            return <a onClick={() => { this.setState({ serverFilter: 
addFilter(serverFilter, 'server_type', value) }); }}>{value}</a>;
+          },
+          show: serverTableColumnSelectionHandler.showColumn('Type')
+        },
+        {
           Header: 'Tier',
           accessor: 'tier',
           Cell: row => {
@@ -257,18 +289,41 @@ WHERE "server_type" = 'historical'`);
           show: serverTableColumnSelectionHandler.showColumn('Tier')
         },
         {
+          Header: 'Host',
+          accessor: 'host',
+          Aggregated: () => '',
+          show: serverTableColumnSelectionHandler.showColumn('Host')
+        },
+        {
+          Header: 'Port',
+          id: 'port',
+          accessor: (row) => {
+            const ports: string[] = [];
+            if (row.plaintext_port !== -1) {
+              ports.push(`${row.plaintext_port} (plain)`);
+            }
+            if (row.tls_port !== -1) {
+              ports.push(`${row.tls_port} (TLS)`);
+            }
+            return ports.join(', ') || 'No port';
+          },
+          Aggregated: () => '',
+          show: serverTableColumnSelectionHandler.showColumn('Port')
+        },
+        {
           Header: 'Curr size',
           id: 'curr_size',
           width: 100,
           filterable: false,
           accessor: 'curr_size',
           Aggregated: row => {
+            if (row.row._pivotVal !== 'historical') return '';
             const originals = row.subRows.map(r => r._original);
             const totalCurr = sum(originals, s => s.curr_size);
             return formatBytes(totalCurr);
           },
           Cell: row => {
-            if (row.aggregated) return '';
+            if (row.aggregated || row.original.server_type !== 'historical') 
return '';
             if (row.value === null) return '';
             return formatBytes(row.value);
           },
@@ -281,12 +336,13 @@ WHERE "server_type" = 'historical'`);
           filterable: false,
           accessor: 'max_size',
           Aggregated: row => {
+            if (row.row._pivotVal !== 'historical') return '';
             const originals = row.subRows.map(r => r._original);
             const totalMax = sum(originals, s => s.max_size);
             return formatBytes(totalMax);
           },
           Cell: row => {
-            if (row.aggregated) return '';
+            if (row.aggregated || row.original.server_type !== 'historical') 
return '';
             if (row.value === null) return '';
             return formatBytes(row.value);
           },
@@ -297,32 +353,92 @@ WHERE "server_type" = 'historical'`);
           id: 'usage',
           width: 100,
           filterable: false,
-          accessor: (row) => row.max_size ? (row.curr_size / row.max_size) : 
null,
+          accessor: (row) => {
+            if (row.server_type === 'middle_manager') {
+              return row.worker ? row.currCapacityUsed / row.worker.capacity : 
null;
+            } else {
+              return row.max_size ? (row.curr_size / row.max_size) : null;
+            }
+          },
           Aggregated: row => {
-            const originals = row.subRows.map(r => r._original);
-            const totalCurr = sum(originals, s => s.curr_size);
-            const totalMax = sum(originals, s => s.max_size);
-            return fillIndicator(totalCurr / totalMax);
+            switch (row.row._pivotVal) {
+              case 'historical':
+                const originalHistoricals = row.subRows.map(r => r._original);
+                const totalCurr = sum(originalHistoricals, s => s.curr_size);
+                const totalMax = sum(originalHistoricals, s => s.max_size);
+                return fillIndicator(totalCurr / totalMax);
+
+              case 'middle_manager':
+                const originalMiddleManagers = row.subRows.map(r => 
r._original);
+                const totalCurrCapacityUsed = sum(originalMiddleManagers, s => 
s.currCapacityUsed || 0);
+                const totalWorkerCapacity = sum(originalMiddleManagers, s => 
deepGet(s, 'worker.capacity') || 0);
+                return `${totalCurrCapacityUsed} / ${totalWorkerCapacity} 
(total slots)`;
+
+              default:
+                return '';
+            }
           },
           Cell: row => {
             if (row.aggregated) return '';
-            if (row.value === null) return '';
-            return fillIndicator(row.value);
+            const { server_type } = row.original;
+            switch (server_type) {
+              case 'historical':
+                return fillIndicator(row.value);
+
+              case 'middle_manager':
+                const currCapacityUsed = deepGet(row, 
'original.currCapacityUsed') || 0;
+                const capacity = deepGet(row, 'original.worker.capacity');
+                if (typeof capacity === 'number') {
+                  return `${currCapacityUsed} / ${capacity} (slots)`;
+                } else {
+                  return '- / -';
+                }
+
+              default:
+                return '';
+            }
           },
           show: serverTableColumnSelectionHandler.showColumn('Usage')
         },
         {
-          Header: 'Load/drop queues',
+          Header: 'Detail',
           id: 'queue',
           width: 400,
           filterable: false,
-          accessor: (row) => (row.segmentsToLoad || 0) + (row.segmentsToDrop 
|| 0),
+          accessor: (row) => {
+            if (row.server_type === 'middle_manager') {
+              if (deepGet(row, 'worker.version') === '') return 'Disabled';
+
+              const details: string[] = [];
+              if (row.lastCompletedTaskTime) {
+                details.push(`Last completed task: 
${row.lastCompletedTaskTime}`);
+              }
+              if (row.blacklistedUntil) {
+                details.push(`Blacklisted until: ${row.blacklistedUntil}`);
+              }
+              return details.join(' ');
+
+            } else {
+              return (row.segmentsToLoad || 0) + (row.segmentsToDrop || 0);
+            }
+          },
           Cell: (row => {
             if (row.aggregated) return '';
-            const { segmentsToLoad, segmentsToLoadSize, segmentsToDrop, 
segmentsToDropSize } = row.original;
-            return formatQueues(segmentsToLoad, segmentsToLoadSize, 
segmentsToDrop, segmentsToDropSize);
+            const { server_type } = row.original;
+            switch (server_type) {
+              case 'historical':
+                const { segmentsToLoad, segmentsToLoadSize, segmentsToDrop, 
segmentsToDropSize } = row.original;
+                return formatQueues(segmentsToLoad, segmentsToLoadSize, 
segmentsToDrop, segmentsToDropSize);
+
+              case 'middle_manager':
+                return row.value;
+
+              default:
+                return '';
+            }
           }),
           Aggregated: row => {
+            if (row.row._pivotVal !== 'historical') return '';
             const originals = row.subRows.map(r => r._original);
             const segmentsToLoad = sum(originals, s => s.segmentsToLoad);
             const segmentsToLoadSize = sum(originals, s => 
s.segmentsToLoadSize);
@@ -330,138 +446,26 @@ WHERE "server_type" = 'historical'`);
             const segmentsToDropSize = sum(originals, s => 
s.segmentsToDropSize);
             return formatQueues(segmentsToLoad, segmentsToLoadSize, 
segmentsToDrop, segmentsToDropSize);
           },
-          show: serverTableColumnSelectionHandler.showColumn('Load/drop 
queues')
-        },
-        {
-          Header: 'Host',
-          accessor: 'host',
-          Aggregated: () => '',
-          show: serverTableColumnSelectionHandler.showColumn('Host')
+          show: serverTableColumnSelectionHandler.showColumn('Detail')
         },
         {
-          Header: 'Port',
-          id: 'port',
-          accessor: (row) => {
-            const ports: string[] = [];
-            if (row.plaintext_port !== -1) {
-              ports.push(`${row.plaintext_port} (plain)`);
-            }
-            if (row.tls_port !== -1) {
-              ports.push(`${row.tls_port} (TLS)`);
-            }
-            return ports.join(', ') || 'No port';
+          Header: ActionCell.COLUMN_LABEL,
+          id: ActionCell.COLUMN_ID,
+          width: ActionCell.COLUMN_WIDTH,
+          accessor: (row) => row.worker,
+          filterable: false,
+          Cell: row => {
+            if (!row.value) return null;
+            const disabled = row.value.version === '';
+            const workerActions = this.getWorkerActions(row.value.host, 
disabled);
+            return <ActionCell actions={workerActions}/>;
           },
-          Aggregated: () => '',
-          show: serverTableColumnSelectionHandler.showColumn('Port')
+          show: 
serverTableColumnSelectionHandler.showColumn(ActionCell.COLUMN_LABEL)
         }
       ]}
-      defaultPageSize={10}
-      className="-striped -highlight"
     />;
   }
 
-  renderMiddleManagerTable() {
-    const { goToTask } = this.props;
-    const { middleManagers, middleManagersLoading, middleManagersError, 
middleManagerFilter } = this.state;
-    const { middleManagerTableColumnSelectionHandler } = this;
-
-    return <>
-      <ReactTable
-        data={middleManagers || []}
-        loading={middleManagersLoading}
-        noDataText={!middleManagersLoading && middleManagers && 
!middleManagers.length ? 'No MiddleManagers' : (middleManagersError || '')}
-        filterable
-        filtered={middleManagerFilter}
-        onFilteredChange={(filtered, column) => {
-          this.setState({ middleManagerFilter: filtered });
-        }}
-        columns={[
-          {
-            Header: 'Host',
-            id: 'host',
-            accessor: (row) => row.worker.host,
-            Cell: row => {
-              const value = row.value;
-              return <a onClick={() => { this.setState({ middleManagerFilter: 
addFilter(middleManagerFilter, 'host', value) }); }}>{value}</a>;
-            },
-            show: middleManagerTableColumnSelectionHandler.showColumn('Host')
-          },
-          {
-            Header: 'Usage',
-            id: 'usage',
-            width: 60,
-            accessor: (row) => `${row.currCapacityUsed} / 
${row.worker.capacity}`,
-            filterable: false,
-            show: middleManagerTableColumnSelectionHandler.showColumn('Usage')
-          },
-          {
-            Header: 'Availability groups',
-            id: 'availabilityGroups',
-            width: 60,
-            accessor: (row) => row.availabilityGroups.length,
-            filterable: false,
-            show: 
middleManagerTableColumnSelectionHandler.showColumn('Availability groups')
-          },
-          {
-            Header: 'Last completed task time',
-            accessor: 'lastCompletedTaskTime',
-            show: middleManagerTableColumnSelectionHandler.showColumn('Last 
completed task time')
-          },
-          {
-            Header: 'Blacklisted until',
-            accessor: 'blacklistedUntil',
-            show: 
middleManagerTableColumnSelectionHandler.showColumn('Blacklisted until')
-          },
-          {
-            Header: 'Status',
-            id: 'status',
-            accessor: (row) => row.worker.version === '' ? 'Disabled' : 
'Enabled',
-            show: middleManagerTableColumnSelectionHandler.showColumn('Status')
-          },
-          {
-            Header: 'Actions',
-            id: 'actions',
-            width: 70,
-            accessor: (row) => row.worker,
-            filterable: false,
-            Cell: row => {
-              const disabled = row.value.version === '';
-              const workerActions = this.getWorkerActions(row.value.host, 
disabled);
-              const workerMenu = basicActionsToMenu(workerActions);
-
-              return <ActionCell>
-                {
-                   workerMenu &&
-                   <Popover content={workerMenu} 
position={Position.BOTTOM_RIGHT}>
-                     <Icon icon={IconNames.WRENCH}/>
-                   </Popover>
-                }
-              </ActionCell>;
-            },
-            show: 
middleManagerTableColumnSelectionHandler.showColumn('Actions')
-          }
-        ]}
-        defaultPageSize={10}
-        className="-striped -highlight"
-        SubComponent={rowInfo => {
-          const runningTasks = rowInfo.original.runningTasks;
-          return <div style={{ padding: '20px' }}>
-            {
-              runningTasks.length ?
-                <>
-                  <span>Running tasks:</span>
-                  <ul>{runningTasks.map((t: string) => <li key={t}>{t}&nbsp;<a 
onClick={() => goToTask(t)}>&#x279A;</a></li>)}</ul>
-                </> :
-                <span>No running tasks</span>
-            }
-          </div>;
-        }}
-      />
-      {this.renderDisableWorkerAction()}
-      {this.renderEnableWorkerAction()}
-    </>;
-  }
-
   private getWorkerActions(workerHost: string, disabled: boolean): 
BasicAction[] {
     if (disabled) {
       return [
@@ -498,7 +502,7 @@ WHERE "server_type" = 'historical'`);
       intent={Intent.DANGER}
       onClose={(success) => {
         this.setState({ middleManagerDisableWorkerHost: null });
-        if (success) this.middleManagerQueryManager.rerunLastQuery();
+        if (success) this.serverQueryManager.rerunLastQuery();
       }}
     >
       <p>
@@ -523,7 +527,7 @@ WHERE "server_type" = 'historical'`);
       intent={Intent.PRIMARY}
       onClose={(success) => {
         this.setState({ middleManagerEnableWorkerHost: null });
-        if (success) this.middleManagerQueryManager.rerunLastQuery();
+        if (success) this.serverQueryManager.rerunLastQuery();
       }}
     >
       <p>
@@ -534,61 +538,39 @@ WHERE "server_type" = 'historical'`);
 
   render() {
     const { goToSql, noSqlMode } = this.props;
-    const { groupByTier } = this.state;
-    const { serverTableColumnSelectionHandler, 
middleManagerTableColumnSelectionHandler } = this;
-
-    return <SplitterLayout
-      customClassName={'servers-view app-view'}
-      vertical
-      percentage
-      
secondaryInitialSize={Number(localStorageGet(LocalStorageKeys.SERVERS_VIEW_PANE_SIZE)
 as string)}
-      primaryMinSize={30}
-      secondaryMinSize={30}
-      onSecondaryPaneSizeChange={this.onSecondaryPaneSizeChange}
-    >
-      <div className={'top-pane'}>
-        <ViewControlBar label="Historicals">
-          <Button
-            icon={IconNames.REFRESH}
-            text="Refresh"
-            onClick={() => this.serverQueryManager.rerunLastQuery()}
-          />
-          {
-            !noSqlMode &&
-            <Button
-              icon={IconNames.APPLICATION}
-              text="Go to SQL"
-              onClick={() => goToSql(this.serverQueryManager.getLastQuery())}
-            />
-          }
-          <Switch
-            checked={groupByTier}
-            label="Group by tier"
-            onChange={() => this.setState({ groupByTier: !groupByTier })}
-          />
-          <TableColumnSelection
-            columns={serverTableColumns}
-            onChange={(column) => 
serverTableColumnSelectionHandler.changeTableColumnSelection(column)}
-            
tableColumnsHidden={serverTableColumnSelectionHandler.hiddenColumns}
-          />
-        </ViewControlBar>
-        {this.renderServersTable()}
-      </div>
-      <div className={'bottom-pane'}>
-        <ViewControlBar label="MiddleManagers">
+    const { groupServersBy } = this.state;
+    const { serverTableColumnSelectionHandler } = this;
+
+    return <div className="servers-view app-view">
+      <ViewControlBar label="Servers">
+        <Label>Group by</Label>
+        <ButtonGroup>
+          <Button active={groupServersBy === null} onClick={() => 
this.setState({ groupServersBy: null })}>None</Button>
+          <Button active={groupServersBy === 'server_type'} onClick={() => 
this.setState({ groupServersBy: 'server_type' })}>Type</Button>
+          <Button active={groupServersBy === 'tier'} onClick={() => 
this.setState({ groupServersBy: 'tier' })}>Tier</Button>
+        </ButtonGroup>
+        <Button
+          icon={IconNames.REFRESH}
+          text="Refresh"
+          onClick={() => this.serverQueryManager.rerunLastQuery()}
+        />
+        {
+          !noSqlMode &&
           <Button
-            icon={IconNames.REFRESH}
-            text="Refresh"
-            onClick={() => this.middleManagerQueryManager.rerunLastQuery()}
+            icon={IconNames.APPLICATION}
+            text="Go to SQL"
+            onClick={() => goToSql(this.serverQueryManager.getLastQuery())}
           />
-          <TableColumnSelection
-            columns={middleManagerTableColumns}
-            onChange={(column) => 
middleManagerTableColumnSelectionHandler.changeTableColumnSelection(column)}
-            
tableColumnsHidden={middleManagerTableColumnSelectionHandler.hiddenColumns}
-          />
-        </ViewControlBar>
-        {this.renderMiddleManagerTable()}
-      </div>
-    </SplitterLayout>;
+        }
+        <TableColumnSelection
+          columns={serverTableColumns}
+          onChange={(column) => 
serverTableColumnSelectionHandler.changeTableColumnSelection(column)}
+          tableColumnsHidden={serverTableColumnSelectionHandler.hiddenColumns}
+        />
+      </ViewControlBar>
+      {this.renderServersTable()}
+      {this.renderDisableWorkerAction()}
+      {this.renderEnableWorkerAction()}
+    </div>;
   }
 }
diff --git 
a/web-console/src/views/sql-view/__snapshots__/sql-view.spec.tsx.snap 
b/web-console/src/views/sql-view/__snapshots__/sql-view.spec.tsx.snap
index 54973fc..fa514ed 100644
--- a/web-console/src/views/sql-view/__snapshots__/sql-view.spec.tsx.snap
+++ b/web-console/src/views/sql-view/__snapshots__/sql-view.spec.tsx.snap
@@ -1,147 +1,164 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`describe sql view sql view snapshot 1`] = `
-<div
-  className="sql-view app-view"
+<t
+  customClassName="sql-view app-view"
+  onDragEnd={null}
+  onDragStart={null}
+  onSecondaryPaneSizeChange={[Function]}
+  percentage={true}
+  primaryIndex={0}
+  primaryMinSize={30}
+  secondaryInitialSize={60}
+  secondaryMinSize={30}
+  vertical={true}
 >
-  <SqlControl
-    initSql="test"
-    onExplain={[Function]}
-    onRun={[Function]}
-    queryElapsed={null}
-  />
-  <ReactTable
-    AggregatedComponent={[Function]}
-    ExpanderComponent={[Function]}
-    FilterComponent={[Function]}
-    LoadingComponent={[Function]}
-    NoDataComponent={[Function]}
-    PadRowComponent={[Function]}
-    PaginationComponent={[Function]}
-    PivotValueComponent={[Function]}
-    ResizerComponent={[Function]}
-    TableComponent={[Function]}
-    TbodyComponent={[Function]}
-    TdComponent={[Function]}
-    TfootComponent={[Function]}
-    ThComponent={[Function]}
-    TheadComponent={[Function]}
-    TrComponent={[Function]}
-    TrGroupComponent={[Function]}
-    aggregatedKey="_aggregated"
-    className="-striped -highlight"
-    collapseOnDataChange={true}
-    collapseOnPageChange={true}
-    collapseOnSortingChange={true}
-    column={
-      Object {
-        "Aggregated": undefined,
-        "Cell": undefined,
-        "Expander": undefined,
-        "Filter": undefined,
-        "Footer": undefined,
-        "Header": undefined,
-        "Pivot": undefined,
-        "PivotValue": undefined,
-        "aggregate": undefined,
-        "className": "",
-        "filterAll": false,
-        "filterMethod": undefined,
-        "filterable": undefined,
-        "footerClassName": "",
-        "footerStyle": Object {},
-        "getFooterProps": [Function],
-        "getHeaderProps": [Function],
-        "getProps": [Function],
-        "headerClassName": "",
-        "headerStyle": Object {},
-        "minWidth": 100,
-        "resizable": undefined,
-        "show": true,
-        "sortMethod": undefined,
-        "sortable": undefined,
-        "style": Object {},
+  <div
+    className="top-pane"
+  >
+    <SqlControl
+      initSql="test"
+      onExplain={[Function]}
+      onRun={[Function]}
+      queryElapsed={null}
+    />
+  </div>
+  <div
+    className="bottom-pane"
+  >
+    <ReactTable
+      AggregatedComponent={[Function]}
+      ExpanderComponent={[Function]}
+      FilterComponent={[Function]}
+      LoadingComponent={[Function]}
+      NoDataComponent={[Function]}
+      PadRowComponent={[Function]}
+      PaginationComponent={[Function]}
+      PivotValueComponent={[Function]}
+      ResizerComponent={[Function]}
+      TableComponent={[Function]}
+      TbodyComponent={[Function]}
+      TdComponent={[Function]}
+      TfootComponent={[Function]}
+      ThComponent={[Function]}
+      TheadComponent={[Function]}
+      TrComponent={[Function]}
+      TrGroupComponent={[Function]}
+      aggregatedKey="_aggregated"
+      className=""
+      collapseOnDataChange={true}
+      collapseOnPageChange={true}
+      collapseOnSortingChange={true}
+      column={
+        Object {
+          "Aggregated": undefined,
+          "Cell": undefined,
+          "Expander": undefined,
+          "Filter": undefined,
+          "Footer": undefined,
+          "Header": undefined,
+          "Pivot": undefined,
+          "PivotValue": undefined,
+          "aggregate": undefined,
+          "className": "",
+          "filterAll": false,
+          "filterMethod": undefined,
+          "filterable": undefined,
+          "footerClassName": "",
+          "footerStyle": Object {},
+          "getFooterProps": [Function],
+          "getHeaderProps": [Function],
+          "getProps": [Function],
+          "headerClassName": "",
+          "headerStyle": Object {},
+          "minWidth": 100,
+          "resizable": undefined,
+          "show": true,
+          "sortMethod": undefined,
+          "sortable": undefined,
+          "style": Object {},
+        }
       }
-    }
-    columns={Array []}
-    data={Array []}
-    defaultExpanded={Object {}}
-    defaultFilterMethod={[Function]}
-    defaultFiltered={Array []}
-    defaultPageSize={10}
-    defaultResized={Array []}
-    defaultSortDesc={false}
-    defaultSortMethod={[Function]}
-    defaultSorted={Array []}
-    expanderDefaults={
-      Object {
-        "filterable": false,
-        "resizable": false,
-        "sortable": false,
-        "width": 35,
+      columns={Array []}
+      data={Array []}
+      defaultExpanded={Object {}}
+      defaultFilterMethod={[Function]}
+      defaultFiltered={Array []}
+      defaultPageSize={20}
+      defaultResized={Array []}
+      defaultSortDesc={false}
+      defaultSortMethod={[Function]}
+      defaultSorted={Array []}
+      expanderDefaults={
+        Object {
+          "filterable": false,
+          "resizable": false,
+          "sortable": false,
+          "width": 35,
+        }
       }
-    }
-    filterable={false}
-    freezeWhenExpanded={false}
-    getLoadingProps={[Function]}
-    getNoDataProps={[Function]}
-    getPaginationProps={[Function]}
-    getProps={[Function]}
-    getResizerProps={[Function]}
-    getTableProps={[Function]}
-    getTbodyProps={[Function]}
-    getTdProps={[Function]}
-    getTfootProps={[Function]}
-    getTfootTdProps={[Function]}
-    getTfootTrProps={[Function]}
-    getTheadFilterProps={[Function]}
-    getTheadFilterThProps={[Function]}
-    getTheadFilterTrProps={[Function]}
-    getTheadGroupProps={[Function]}
-    getTheadGroupThProps={[Function]}
-    getTheadGroupTrProps={[Function]}
-    getTheadProps={[Function]}
-    getTheadThProps={[Function]}
-    getTheadTrProps={[Function]}
-    getTrGroupProps={[Function]}
-    getTrProps={[Function]}
-    groupedByPivotKey="_groupedByPivot"
-    indexKey="_index"
-    loading={false}
-    loadingText="Loading..."
-    multiSort={true}
-    nestingLevelKey="_nestingLevel"
-    nextText="Next"
-    noDataText=""
-    ofText="of"
-    onFetchData={[Function]}
-    originalKey="_original"
-    pageSizeOptions={
-      Array [
-        5,
-        10,
-        20,
-        25,
-        50,
-        100,
-      ]
-    }
-    pageText="Page"
-    pivotDefaults={Object {}}
-    pivotIDKey="_pivotID"
-    pivotValKey="_pivotVal"
-    previousText="Previous"
-    resizable={true}
-    resolveData={[Function]}
-    rowsText="rows"
-    showPageJump={true}
-    showPageSizeOptions={true}
-    showPagination={true}
-    showPaginationBottom={true}
-    showPaginationTop={false}
-    sortable={false}
-    style={Object {}}
-    subRowsKey="_subRows"
-  />
-</div>
+      filterable={false}
+      freezeWhenExpanded={false}
+      getLoadingProps={[Function]}
+      getNoDataProps={[Function]}
+      getPaginationProps={[Function]}
+      getProps={[Function]}
+      getResizerProps={[Function]}
+      getTableProps={[Function]}
+      getTbodyProps={[Function]}
+      getTdProps={[Function]}
+      getTfootProps={[Function]}
+      getTfootTdProps={[Function]}
+      getTfootTrProps={[Function]}
+      getTheadFilterProps={[Function]}
+      getTheadFilterThProps={[Function]}
+      getTheadFilterTrProps={[Function]}
+      getTheadGroupProps={[Function]}
+      getTheadGroupThProps={[Function]}
+      getTheadGroupTrProps={[Function]}
+      getTheadProps={[Function]}
+      getTheadThProps={[Function]}
+      getTheadTrProps={[Function]}
+      getTrGroupProps={[Function]}
+      getTrProps={[Function]}
+      groupedByPivotKey="_groupedByPivot"
+      indexKey="_index"
+      loading={false}
+      loadingText="Loading..."
+      multiSort={true}
+      nestingLevelKey="_nestingLevel"
+      nextText="Next"
+      noDataText=""
+      ofText="of"
+      onFetchData={[Function]}
+      originalKey="_original"
+      pageSizeOptions={
+        Array [
+          5,
+          10,
+          20,
+          25,
+          50,
+          100,
+        ]
+      }
+      pageText="Page"
+      pivotDefaults={Object {}}
+      pivotIDKey="_pivotID"
+      pivotValKey="_pivotVal"
+      previousText="Previous"
+      resizable={true}
+      resolveData={[Function]}
+      rowsText="rows"
+      showPageJump={true}
+      showPageSizeOptions={true}
+      showPagination={true}
+      showPaginationBottom={true}
+      showPaginationTop={false}
+      sortable={false}
+      style={Object {}}
+      subRowsKey="_subRows"
+    />
+  </div>
+</t>
 `;
diff --git a/web-console/src/views/sql-view/sql-view.scss 
b/web-console/src/views/sql-view/sql-view.scss
index 54c9117..f1ef90b 100644
--- a/web-console/src/views/sql-view/sql-view.scss
+++ b/web-console/src/views/sql-view/sql-view.scss
@@ -20,22 +20,38 @@
 
 .sql-view {
   height: 100%;
-  display: flex;
-  flex-direction: column;
+  width: 100%;
 
-  .sql-control {
-    textarea {
+  .top-pane {
+    position: absolute;
+    width: 100%;
+    top: 0;
+    bottom: 10px;
+
+    .sql-control {
+      position: absolute;
       width: 100%;
-      min-height: 180px;
+      height: 100%;
     }
+  }
 
-    .buttons {
-      padding: $standard-padding 0;
-    }
+  &.splitter-layout.splitter-layout-vertical > .layout-splitter {
+    height: 3px;
+    background-color: #6d8ea9;
   }
 
-  .ReactTable {
-    flex: 1;
+  .bottom-pane {
+    position: absolute;
+    width: 100%;
+    top: 10px;
+    bottom: 0;
+
+    .ReactTable {
+      position: absolute;
+      top: 0;
+      bottom: 0;
+      width: 100%;
+    }
   }
 }
 
diff --git a/web-console/src/views/sql-view/sql-view.tsx 
b/web-console/src/views/sql-view/sql-view.tsx
index 46be35ac..dbf0f0d 100644
--- a/web-console/src/views/sql-view/sql-view.tsx
+++ b/web-console/src/views/sql-view/sql-view.tsx
@@ -18,10 +18,11 @@
 
 import * as Hjson from 'hjson';
 import * as React from 'react';
+import SplitterLayout from 'react-splitter-layout';
 import ReactTable from 'react-table';
 
-import { NullTableCell, SqlControl } from '../../components/index';
-import { QueryPlanDialog } from '../../dialogs/index';
+import { NullTableCell, SqlControl } from '../../components';
+import { QueryPlanDialog } from '../../dialogs';
 import {
   BasicQueryExplanation,
   decodeRune,
@@ -35,9 +36,9 @@ import {
 
 import './sql-view.scss';
 
-interface QueryWithFlags {
+interface QueryWithContext {
   queryString: string;
-  bypassCache?: boolean;
+  context?: Record<string, any>;
   wrapQuery?: boolean;
 }
 
@@ -62,9 +63,13 @@ interface SqlQueryResult {
 }
 
 export class SqlView extends React.Component<SqlViewProps, SqlViewState> {
+  static trimSemicolon(query: string): string {
+    // Trims out a trailing semicolon while preserving space 
(https://bit.ly/1n1yfkJ)
+    return query.replace(/;+(\s*)$/, '$1');
+  }
 
-  private sqlQueryManager: QueryManager<QueryWithFlags, SqlQueryResult>;
-  private explainQueryManager: QueryManager<string, any>;
+  private sqlQueryManager: QueryManager<QueryWithContext, SqlQueryResult>;
+  private explainQueryManager: QueryManager<QueryWithContext, 
BasicQueryExplanation | SemiJoinQueryExplanation | string>;
 
   constructor(props: SqlViewProps, context: any) {
     super(props, context);
@@ -82,20 +87,15 @@ export class SqlView extends React.Component<SqlViewProps, 
SqlViewState> {
 
   componentDidMount(): void {
     this.sqlQueryManager = new QueryManager({
-      processQuery: async (queryWithFlags: QueryWithFlags) => {
-        const { queryString, bypassCache, wrapQuery } = queryWithFlags;
+      processQuery: async (queryWithContext: QueryWithContext) => {
+        const { queryString, context, wrapQuery } = queryWithContext;
         const startTime = new Date();
 
         if (queryString.trim().startsWith('{')) {
           // Secret way to issue a native JSON "rune" query
           const runeQuery = Hjson.parse(queryString);
 
-          if (bypassCache) {
-            runeQuery.context = runeQuery.context || {};
-            runeQuery.context.useCache = false;
-            runeQuery.context.populateCache = false;
-          }
-
+          if (context) runeQuery.context = context;
           const result = await queryDruidRune(runeQuery);
           return {
             queryResult: decodeRune(runeQuery, result),
@@ -104,7 +104,7 @@ export class SqlView extends React.Component<SqlViewProps, 
SqlViewState> {
 
         } else {
           const actualQuery = wrapQuery ?
-            `SELECT * FROM (${queryString.replace(/;+(\s*)$/, '$1')}) LIMIT 
2000` :
+            `SELECT * FROM (${SqlView.trimSemicolon(queryString)}) LIMIT 2000` 
:
             queryString;
 
           const queryPayload: Record<string, any> = {
@@ -113,13 +113,7 @@ export class SqlView extends React.Component<SqlViewProps, 
SqlViewState> {
             header: true
           };
 
-          if (wrapQuery) {
-            queryPayload.context = {
-              useCache: false,
-              populateCache: false
-            };
-          }
-
+          if (context) queryPayload.context = context;
           const result = await queryDruidSql(queryPayload);
 
           return {
@@ -142,14 +136,17 @@ export class SqlView extends 
React.Component<SqlViewProps, SqlViewState> {
     });
 
     this.explainQueryManager = new QueryManager({
-      processQuery: async (query: string) => {
-        const explainQuery = `explain plan for ${query}`;
-        const result = await queryDruidSql({
-          query: explainQuery,
+      processQuery: async (queryWithContext: QueryWithContext) => {
+        const { queryString, context } = queryWithContext;
+        const explainPayload: Record<string, any> = {
+          query: `EXPLAIN PLAN FOR (${SqlView.trimSemicolon(queryString)})`,
           resultFormat: 'object'
-        });
-        const data: BasicQueryExplanation | SemiJoinQueryExplanation | string 
= parseQueryPlan(result[0]['PLAN']);
-        return data;
+        };
+
+        if (context) explainPayload.context = context;
+        const result = await queryDruidSql(explainPayload);
+
+        return parseQueryPlan(result[0]['PLAN']);
       },
       onStateChange: ({ result, loading, error }) => {
         this.setState({
@@ -166,13 +163,8 @@ export class SqlView extends React.Component<SqlViewProps, 
SqlViewState> {
     this.explainQueryManager.terminate();
   }
 
-  getExplain = (q: string) => {
-    this.setState({
-      explainDialogOpen: true,
-      loadingExplain: true,
-      explainError: null
-    });
-    this.explainQueryManager.runQuery(q);
+  onSecondaryPaneSizeChange(secondaryPaneSize: number) {
+    localStorageSet(LocalStorageKeys.QUERY_VIEW_PANE_SIZE, 
String(secondaryPaneSize));
   }
 
   renderExplainDialog() {
@@ -204,8 +196,6 @@ export class SqlView extends React.Component<SqlViewProps, 
SqlViewState> {
           };
         })
       }
-      defaultPageSize={10}
-      className="-striped -highlight"
     />;
   }
 
@@ -213,18 +203,33 @@ export class SqlView extends 
React.Component<SqlViewProps, SqlViewState> {
     const { initSql } = this.props;
     const { queryElapsed } = this.state;
 
-    return <div className="sql-view app-view">
-      <SqlControl
-        initSql={initSql || localStorageGet(LocalStorageKeys.QUERY_KEY)}
-        onRun={(queryString, bypassCache, wrapQuery) => {
-          localStorageSet(LocalStorageKeys.QUERY_KEY, queryString);
-          this.sqlQueryManager.runQuery({ queryString, bypassCache, wrapQuery 
});
-        }}
-        onExplain={this.getExplain}
-        queryElapsed={queryElapsed}
-      />
-      {this.renderResultTable()}
-      {this.renderExplainDialog()}
-    </div>;
+    return <SplitterLayout
+      customClassName="sql-view app-view"
+      vertical
+      percentage
+      
secondaryInitialSize={Number(localStorageGet(LocalStorageKeys.QUERY_VIEW_PANE_SIZE)
 as string) || 60}
+      primaryMinSize={30}
+      secondaryMinSize={30}
+      onSecondaryPaneSizeChange={this.onSecondaryPaneSizeChange}
+    >
+      <div className="top-pane">
+        <SqlControl
+          initSql={initSql || localStorageGet(LocalStorageKeys.QUERY_KEY)}
+          onRun={(queryString, context, wrapQuery) => {
+            localStorageSet(LocalStorageKeys.QUERY_KEY, queryString);
+            this.sqlQueryManager.runQuery({ queryString, context, wrapQuery });
+          }}
+          onExplain={(queryString, context) => {
+            this.setState({ explainDialogOpen: true });
+            this.explainQueryManager.runQuery({ queryString, context });
+          }}
+          queryElapsed={queryElapsed}
+        />
+      </div>
+      <div className="bottom-pane">
+        {this.renderResultTable()}
+        {this.renderExplainDialog()}
+      </div>
+    </SplitterLayout>;
   }
 }
diff --git 
a/web-console/src/views/task-view/__snapshots__/tasks-view.spec.tsx.snap 
b/web-console/src/views/task-view/__snapshots__/tasks-view.spec.tsx.snap
index 16b7b90..aaef769 100644
--- a/web-console/src/views/task-view/__snapshots__/tasks-view.spec.tsx.snap
+++ b/web-console/src/views/task-view/__snapshots__/tasks-view.spec.tsx.snap
@@ -63,7 +63,7 @@ exports[`describe tasks view tasks view snapshot 1`] = `
         TrComponent={[Function]}
         TrGroupComponent={[Function]}
         aggregatedKey="_aggregated"
-        className="-striped -highlight"
+        className=""
         collapseOnDataChange={true}
         collapseOnPageChange={true}
         collapseOnSortingChange={true}
@@ -140,7 +140,7 @@ exports[`describe tasks view tasks view snapshot 1`] = `
         defaultExpanded={Object {}}
         defaultFilterMethod={[Function]}
         defaultFiltered={Array []}
-        defaultPageSize={5}
+        defaultPageSize={20}
         defaultResized={Array []}
         defaultSortDesc={false}
         defaultSortMethod={[Function]}
@@ -392,7 +392,7 @@ exports[`describe tasks view tasks view snapshot 1`] = `
         TrComponent={[Function]}
         TrGroupComponent={[Function]}
         aggregatedKey="_aggregated"
-        className="-striped -highlight"
+        className=""
         collapseOnDataChange={true}
         collapseOnPageChange={true}
         collapseOnSortingChange={true}
diff --git a/web-console/src/views/task-view/tasks-view.scss 
b/web-console/src/views/task-view/tasks-view.scss
index c22ae9c..e7161b1 100644
--- a/web-console/src/views/task-view/tasks-view.scss
+++ b/web-console/src/views/task-view/tasks-view.scss
@@ -22,27 +22,33 @@
   height: 100%;
   width: 100%;
 
+  .top-pane {
+    position: absolute;
+    width: 100%;
+    top: 0;
+    bottom: 0;
+
+    .view-control-bar {
+      margin-bottom: $standard-padding;
+    }
+  }
+
+  &.splitter-layout.splitter-layout-vertical > .layout-splitter {
+    height: 3px;
+    background-color: #6d8ea9;
+  }
 
-  .view-control-bar{
-    margin-bottom: $standard-padding;
+  .bottom-pane {
+    position: absolute;
+    width: 100%;
+    top: 12px;
+    bottom: 0;
   }
 
   .ReactTable {
     position: absolute;
-    top: 50px;
+    top: $view-control-bar-height + $standard-padding;
     bottom: 0;
     width: 100%;
   }
-
-}
-
-.bottom-pane {
-  position: relative;
-  height: 100%;
-  padding-top: 15px;
-}
-
-.splitter-layout.splitter-layout-vertical > .layout-splitter{
-  height: 2px;
-  background-color: #6d8ea9;
 }
diff --git a/web-console/src/views/task-view/tasks-view.tsx 
b/web-console/src/views/task-view/tasks-view.tsx
index e07c27b..942677e 100644
--- a/web-console/src/views/task-view/tasks-view.tsx
+++ b/web-console/src/views/task-view/tasks-view.tsx
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { Alert, Button, ButtonGroup, Icon, Intent, Label, Menu, MenuDivider, 
MenuItem, Popover, Position } from '@blueprintjs/core';
+import { Alert, Button, ButtonGroup, Intent, Label, Menu, MenuItem, Popover, 
Position } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
 import * as React from 'react';
@@ -24,8 +24,8 @@ import SplitterLayout from 'react-splitter-layout';
 import ReactTable from 'react-table';
 import { Filter } from 'react-table';
 
-import { ActionCell, TableColumnSelection, ViewControlBar} from 
'../../components/index';
-import { AsyncActionDialog, SpecDialog, SupervisorTableActionDialog, 
TaskTableActionDialog } from '../../dialogs/index';
+import { ActionCell, TableColumnSelection, ViewControlBar} from 
'../../components';
+import { AsyncActionDialog, SpecDialog, SupervisorTableActionDialog, 
TaskTableActionDialog } from '../../dialogs';
 import { AppToaster } from '../../singletons/toaster';
 import {
   addFilter,
@@ -36,12 +36,12 @@ import {
   queryDruidSql,
   QueryManager, TableColumnSelectionHandler
 } from '../../utils';
-import { BasicAction, basicActionsToMenu } from '../../utils/basic-action';
+import { BasicAction } from '../../utils/basic-action';
 
 import './tasks-view.scss';
 
-const supervisorTableColumns: string[] = ['Datasource', 'Type', 
'Topic/Stream', 'Status', 'Actions'];
-const taskTableColumns: string[] = ['Task ID', 'Type', 'Datasource', 
'Location', 'Created time', 'Status', 'Duration', 'Actions'];
+const supervisorTableColumns: string[] = ['Datasource', 'Type', 
'Topic/Stream', 'Status', ActionCell.COLUMN_LABEL];
+const taskTableColumns: string[] = ['Task ID', 'Type', 'Datasource', 
'Location', 'Created time', 'Status', 'Duration', ActionCell.COLUMN_LABEL];
 
 export interface TasksViewProps extends React.Props<any> {
   taskId: string | null;
@@ -87,10 +87,10 @@ interface TaskQueryResultRow {
   duration: number;
   error_msg: string | null;
   location: string | null;
-  rank: number;
   status: string;
   task_id: string;
   type: string;
+  rank: number;
 }
 
 interface SupervisorQueryResultRow {
@@ -115,6 +115,7 @@ export class TasksView extends 
React.Component<TasksViewProps, TasksViewState> {
   private supervisorTableColumnSelectionHandler: TableColumnSelectionHandler;
   private taskTableColumnSelectionHandler: TableColumnSelectionHandler;
   static statusRanking: Record<string, number> = {RUNNING: 4, PENDING: 3, 
WAITING: 2, SUCCESS: 1, FAILED: 1};
+
   constructor(props: TasksViewProps, context: any) {
     super(props, context);
     this.state = {
@@ -153,9 +154,6 @@ export class TasksView extends 
React.Component<TasksViewProps, TasksViewState> {
     this.taskTableColumnSelectionHandler = new TableColumnSelectionHandler(
       LocalStorageKeys.TASK_TABLE_COLUMN_SELECTION, () => this.setState({})
     );
-    if (!localStorageGet(LocalStorageKeys.TASKS_VIEW_PANE_SIZE)) {
-      localStorageSet(LocalStorageKeys.TASKS_VIEW_PANE_SIZE, '60');
-    }
   }
 
   static parseTasks = (data: any[]): TaskQueryResultRow[] => {
@@ -166,10 +164,10 @@ export class TasksView extends 
React.Component<TasksViewProps, TasksViewState> {
         duration: d.duration ? d.duration : 0,
         error_msg: d.errorMsg,
         location: d.location.host ? `${d.location.host}:${d.location.port}` : 
null,
-        rank: (TasksView.statusRanking as any)[d.statusCode === 'RUNNING' ? 
d.runnerStatusCode : d.statusCode],
         status: d.statusCode === 'RUNNING' ? d.runnerStatusCode : d.statusCode,
         task_id: d.id,
-        type: d.typTasksView
+        type: d.typTasksView,
+        rank: TasksView.statusRanking[d.statusCode === 'RUNNING' ? 
d.runnerStatusCode : d.statusCode]
       };
     });
   }
@@ -226,12 +224,14 @@ export class TasksView extends 
React.Component<TasksViewProps, TasksViewState> {
     //   FAILED => 1
 
     this.taskQueryManager.runQuery(`SELECT
-  "task_id", "type", "datasource", "created_time",
+  "task_id", "type", "datasource", "created_time", "location", "duration", 
"error_msg",
   CASE WHEN "status" = 'RUNNING' THEN "runner_status" ELSE "status" END AS 
"status",
-  CASE WHEN "status" = 'RUNNING' THEN
-   (CASE WHEN "runner_status" = 'RUNNING' THEN 4 WHEN "runner_status" = 
'PENDING' THEN 3 ELSE 2 END)
-  ELSE 1 END AS "rank",
-   "location", "duration", "error_msg"
+  (
+    CASE WHEN "status" = 'RUNNING' THEN
+     (CASE "runner_status" WHEN 'RUNNING' THEN 4 WHEN 'PENDING' THEN 3 ELSE 2 
END)
+    ELSE 1
+    END
+  ) AS "rank"
 FROM sys.tasks
 ORDER BY "rank" DESC, "created_time" DESC`);
 
@@ -479,39 +479,27 @@ ORDER BY "rank" DESC, "created_time" DESC`);
             show: supervisorTableColumnSelectionHandler.showColumn('Status')
           },
           {
-            Header: 'Actions',
-            id: 'actions',
+            Header: ActionCell.COLUMN_LABEL,
+            id: ActionCell.COLUMN_ID,
             accessor: 'id',
-            width: 70,
+            width: ActionCell.COLUMN_WIDTH,
             filterable: false,
             Cell: row => {
               const id = row.value;
               const type = row.row.type;
               const supervisorSuspended = row.original.spec.suspended;
               const supervisorActions = this.getSupervisorActions(id, 
supervisorSuspended, type);
-              const supervisorMenu = basicActionsToMenu(supervisorActions);
-
-              return <ActionCell>
-                <Icon
-                  icon={IconNames.SEARCH_TEMPLATE}
-                  onClick={() => this.setState({
-                    supervisorTableActionDialogId: id,
-                    supervisorTableActionDialogActions: supervisorActions
-                  })}
-                />
-                {
-                  supervisorMenu &&
-                  <Popover content={supervisorMenu} 
position={Position.BOTTOM_RIGHT}>
-                    <Icon icon={IconNames.WRENCH}/>
-                  </Popover>
-                }
-              </ActionCell>;
+              return <ActionCell
+                onDetail={() => this.setState({
+                  supervisorTableActionDialogId: id,
+                  supervisorTableActionDialogActions: supervisorActions
+                })}
+                actions={supervisorActions}
+              />;
             },
-            show: supervisorTableColumnSelectionHandler.showColumn('Actions')
+            show: 
supervisorTableColumnSelectionHandler.showColumn(ActionCell.COLUMN_LABEL)
           }
         ]}
-        defaultPageSize={5}
-        className="-striped -highlight"
       />
       {this.renderResumeSupervisorAction()}
       {this.renderSuspendSupervisorAction()}
@@ -675,10 +663,10 @@ ORDER BY "rank" DESC, "created_time" DESC`);
             show: taskTableColumnSelectionHandler.showColumn('Duration')
           },
           {
-            Header: 'Actions',
-            id: 'actions',
+            Header: ActionCell.COLUMN_LABEL,
+            id: ActionCell.COLUMN_ID,
             accessor: 'task_id',
-            width: 70,
+            width: ActionCell.COLUMN_WIDTH,
             filterable: false,
             Cell: row => {
               if (row.aggregated) return '';
@@ -686,30 +674,18 @@ ORDER BY "rank" DESC, "created_time" DESC`);
               const type = row.row.type;
               const { status } = row.original;
               const taskActions = this.getTaskActions(id, status, type);
-              const taskMenu = basicActionsToMenu(taskActions);
-
-              return <ActionCell>
-                <Icon
-                  icon={IconNames.SEARCH_TEMPLATE}
-                  onClick={() => this.setState({
-                    taskTableActionDialogId: id,
-                    taskTableActionDialogActions: taskActions
-                  })}
-                />
-                {
-                  taskMenu &&
-                  <Popover content={taskMenu} position={Position.BOTTOM_RIGHT}>
-                    <Icon icon={IconNames.WRENCH}/>
-                  </Popover>
-                }
-              </ActionCell>;
+              return <ActionCell
+                onDetail={() => this.setState({
+                  taskTableActionDialogId: id,
+                  taskTableActionDialogActions: taskActions
+                })}
+                actions={taskActions}
+              />;
             },
             Aggregated: row => '',
-            show: taskTableColumnSelectionHandler.showColumn('Actions')
+            show: 
taskTableColumnSelectionHandler.showColumn(ActionCell.COLUMN_LABEL)
           }
         ]}
-        defaultPageSize={20}
-        className="-striped -highlight"
       />
       {this.renderKillTaskAction()}
     </>;
@@ -736,7 +712,7 @@ ORDER BY "rank" DESC, "created_time" DESC`);
         customClassName={'tasks-view app-view'}
         vertical
         percentage
-        
secondaryInitialSize={Number(localStorageGet(LocalStorageKeys.TASKS_VIEW_PANE_SIZE)
 as string)}
+        
secondaryInitialSize={Number(localStorageGet(LocalStorageKeys.TASKS_VIEW_PANE_SIZE)
 as string) || 60}
         primaryMinSize={30}
         secondaryMinSize={30}
         onSecondaryPaneSizeChange={this.onSecondaryPaneSizeChange}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to