You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by fj...@apache.org on 2019/06/09 17:44:23 UTC

[incubator-druid] branch master updated: Web console: make the data loader more responsive when sampling data with many columns (#7856)

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

fjy 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 c3d230b  Web console: make the data loader more responsive when sampling data with many columns (#7856)
c3d230b is described below

commit c3d230b35475fdfcdc7ed74f17dc02b46f13142b
Author: Vadim Ogievetsky <va...@gmail.com>
AuthorDate: Sun Jun 9 10:44:13 2019 -0700

    Web console: make the data loader more responsive when sampling data with many columns (#7856)
    
    * Don't rerender data loader tables
    
    * removed unused imports
    
    * removed extra console.log
    
    * fix typo
---
 web-console/script/mkcomp                          |   27 +-
 web-console/src/bootstrap/react-table-defaults.tsx |    2 +-
 .../src/components/action-cell/action-cell.tsx     |    2 +-
 .../src/components/action-icon/action-icon.tsx     |    2 +-
 .../src/components/array-input/array-input.tsx     |    2 +-
 .../components/center-message/center-message.tsx   |    2 +-
 .../components/clearable-input/clearable-input.tsx |    2 +-
 .../src/components/external-link/external-link.tsx |    2 +-
 web-console/src/components/index.ts                |    1 -
 .../src/components/menu-checkbox/menu-checkbox.tsx |    2 +-
 .../src/components/table-cell/table-cell.tsx       |    2 +-
 .../view-control-bar/view-control-bar.tsx          |    2 +-
 .../__snapshots__/compaction-dialog.spec.tsx.snap  |    4 +-
 .../table-action-dialog/table-action-dialog.tsx    |    2 +-
 web-console/src/entry.ts                           |    5 +
 web-console/src/utils/general.tsx                  |   18 +
 web-console/src/utils/ingestion-spec.tsx           |   16 +-
 web-console/src/utils/sampler.ts                   |    2 +-
 .../__snapshots__/filter-table.spec.tsx.snap       | 1014 ++++++++++++++
 .../load-data-view/filter-table/filter-table.scss} |   20 +-
 .../filter-table/filter-table.spec.tsx}            |   28 +-
 .../load-data-view/filter-table/filter-table.tsx   |   88 ++
 .../src/views/load-data-view/load-data-view.scss   |   41 -
 .../src/views/load-data-view/load-data-view.tsx    |  486 ++-----
 .../__snapshots__/parse-data-table.spec.tsx.snap   | 1476 ++++++++++++++++++++
 .../parse-data-table/parse-data-table.scss}        |   25 +-
 .../parse-data-table/parse-data-table.spec.tsx}    |   28 +-
 .../parse-data-table/parse-data-table.tsx          |   99 ++
 .../__snapshots__/parse-time-table.spec.tsx.snap   | 1014 ++++++++++++++
 .../parse-time-table/parse-time-table.scss}        |   12 +-
 .../parse-time-table/parse-time-table.spec.tsx}    |   31 +-
 .../parse-time-table/parse-time-table.tsx          |  105 ++
 .../__snapshots__/schema-table.spec.tsx.snap       | 1014 ++++++++++++++
 .../load-data-view/schema-table/schema-table.scss} |   35 +-
 .../schema-table/schema-table.spec.tsx}            |   31 +-
 .../load-data-view/schema-table/schema-table.tsx   |  135 ++
 .../__snapshots__/transform-table.spec.tsx.snap    | 1014 ++++++++++++++
 .../transform-table/transform-table.scss}          |   20 +-
 .../transform-table/transform-table.spec.tsx}      |   28 +-
 .../transform-table/transform-table.tsx            |   92 ++
 .../__snapshots__/sql-control.spec.tsx.snap        |    2 +-
 .../sql-view}/sql-control/sql-control.scss         |    2 +-
 .../sql-view}/sql-control/sql-control.spec.tsx     |    0
 .../sql-view}/sql-control/sql-control.tsx          |   13 +-
 web-console/src/views/sql-view/sql-view.tsx        |    4 +-
 45 files changed, 6420 insertions(+), 532 deletions(-)

diff --git a/web-console/script/mkcomp b/web-console/script/mkcomp
index a2b9bb5..5c60a80 100755
--- a/web-console/script/mkcomp
+++ b/web-console/script/mkcomp
@@ -17,24 +17,20 @@
  * limitations under the License.
  */
 
-let fs = require('fs-extra');
+const fs = require('fs-extra');
 
 if (!(process.argv.length === 3 || process.argv.length === 4)) {
-  console.log('Usage: mkcomp <what?> <component-name>');
+  console.log('Usage: mkcomp <where?> <component-name>');
   process.exit();
 }
 
 let name;
-let what;
+let where;
 if (process.argv.length === 4) {
-  what = process.argv[2];
+  where = process.argv[2];
   name = process.argv[3];
-  if (!(what === 'component' || what === 'dialog' || what === 'singleton')) {
-    console.log(`Bad what, should be on of: component, dialog, singleton`);
-    process.exit();
-  }
 } else {
-  what = 'component';
+  where = 'components';
   name = process.argv[2];
 }
 
@@ -43,7 +39,7 @@ if (!/^([a-z-])+$/.test(name)) {
   process.exit();
 }
 
-let path = `./src/${what}s/${name}/`;
+const path = `./src/${where}/${name}/`;
 fs.ensureDirSync(path);
 console.log('Making path:', path);
 
@@ -85,7 +81,7 @@ writeFile(path + name + '.tsx',
 import { Button, InputGroup } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import classNames from 'classnames';
-import * as React from 'react';
+import React from 'react';
 
 import './${name}.scss';
 
@@ -95,7 +91,7 @@ export interface ${camelName}Props extends React.Props<any> {
 export interface ${camelName}State {
 }
 
-export class ${camelName} extends React.Component<${camelName}Props, ${camelName}State> {
+export class ${camelName} extends React.PureComponent<${camelName}Props, ${camelName}State> {
   constructor(props: ${camelName}Props, context: any) {
     super(props, context);
     // this.state = {};
@@ -155,16 +151,17 @@ writeFile(path + name + '.spec.tsx',
  * limitations under the License.
  */
 
-import * as React from 'react';
+import React from 'react';
 import { render } from 'react-testing-library';
 
 import { ${camelName} } from './${name}';
 
 describe('${spaceName}', () => {
-  it('action cell snapshot', () => {
+  it('matches snapshot', () => {
     const ${snakeName} = <${camelName}
     />;
-    const { container, getByText } = render(${snakeName});
+
+    const { container } = render(${snakeName});
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/bootstrap/react-table-defaults.tsx b/web-console/src/bootstrap/react-table-defaults.tsx
index 5fb69e2..b39d6ec 100644
--- a/web-console/src/bootstrap/react-table-defaults.tsx
+++ b/web-console/src/bootstrap/react-table-defaults.tsx
@@ -19,7 +19,7 @@
 import React from 'react';
 import { Filter, ReactTableDefaults } from 'react-table';
 
-import { Loader } from '../components/loader/loader';
+import { Loader } from '../components';
 import { booleanCustomTableFilter, countBy, makeTextFilter } from '../utils';
 
 import { ReactTableCustomPagination } from './react-table-custom-pagination';
diff --git a/web-console/src/components/action-cell/action-cell.tsx b/web-console/src/components/action-cell/action-cell.tsx
index dbf4952..1daa5df 100644
--- a/web-console/src/components/action-cell/action-cell.tsx
+++ b/web-console/src/components/action-cell/action-cell.tsx
@@ -30,7 +30,7 @@ export interface ActionCellProps extends React.Props<any> {
   actions?: BasicAction[];
 }
 
-export class ActionCell extends React.PureComponent<ActionCellProps, {}> {
+export class ActionCell extends React.PureComponent<ActionCellProps> {
   static COLUMN_ID = 'actions';
   static COLUMN_LABEL = 'Actions';
   static COLUMN_WIDTH = 70;
diff --git a/web-console/src/components/action-icon/action-icon.tsx b/web-console/src/components/action-icon/action-icon.tsx
index 669e285..eb67bfa 100644
--- a/web-console/src/components/action-icon/action-icon.tsx
+++ b/web-console/src/components/action-icon/action-icon.tsx
@@ -28,7 +28,7 @@ export interface ActionIconProps extends React.Props<any> {
   onClick?: () => void;
 }
 
-export class ActionIcon extends React.PureComponent<ActionIconProps, {}> {
+export class ActionIcon extends React.PureComponent<ActionIconProps> {
   render() {
     const { className, icon, onClick } = this.props;
 
diff --git a/web-console/src/components/array-input/array-input.tsx b/web-console/src/components/array-input/array-input.tsx
index 7a2d5d6..6e9f776 100644
--- a/web-console/src/components/array-input/array-input.tsx
+++ b/web-console/src/components/array-input/array-input.tsx
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-import { ITagInputProps, TextArea } from '@blueprintjs/core';
+import { TextArea } from '@blueprintjs/core';
 import React from 'react';
 
 export interface ArrayInputProps {
diff --git a/web-console/src/components/center-message/center-message.tsx b/web-console/src/components/center-message/center-message.tsx
index dc9515b..bae0d89 100644
--- a/web-console/src/components/center-message/center-message.tsx
+++ b/web-console/src/components/center-message/center-message.tsx
@@ -23,7 +23,7 @@ import './center-message.scss';
 export interface CenterMessageProps extends React.Props<any> {
 }
 
-export class CenterMessage extends React.PureComponent<CenterMessageProps, {}> {
+export class CenterMessage extends React.PureComponent<CenterMessageProps> {
   render() {
     return <div className="center-message bp3-input">
       <div className="center-message-inner">
diff --git a/web-console/src/components/clearable-input/clearable-input.tsx b/web-console/src/components/clearable-input/clearable-input.tsx
index 8682a5f..b695bbb 100644
--- a/web-console/src/components/clearable-input/clearable-input.tsx
+++ b/web-console/src/components/clearable-input/clearable-input.tsx
@@ -28,7 +28,7 @@ export interface ClearableInputProps extends React.Props<any> {
   placeholder: string;
 }
 
-export class ClearableInput extends React.PureComponent<ClearableInputProps, {}> {
+export class ClearableInput extends React.PureComponent<ClearableInputProps> {
   render() {
     const { className, value, onChange, placeholder } = this.props;
 
diff --git a/web-console/src/components/external-link/external-link.tsx b/web-console/src/components/external-link/external-link.tsx
index 229d3f7..9dc0562 100644
--- a/web-console/src/components/external-link/external-link.tsx
+++ b/web-console/src/components/external-link/external-link.tsx
@@ -22,7 +22,7 @@ export interface ExternalLinkProps extends React.Props<any> {
   href: string;
 }
 
-export class ExternalLink extends React.PureComponent<ExternalLinkProps, {}> {
+export class ExternalLink extends React.PureComponent<ExternalLinkProps> {
   render() {
     const { href, children } = this.props;
 
diff --git a/web-console/src/components/index.ts b/web-console/src/components/index.ts
index 6a706a7..063875a 100644
--- a/web-console/src/components/index.ts
+++ b/web-console/src/components/index.ts
@@ -30,7 +30,6 @@ export * from './table-cell/table-cell';
 export * from './rule-editor/rule-editor';
 export * from './show-json/show-json';
 export * from './show-log/show-log';
-export * from './sql-control/sql-control';
 export * from './table-column-selector/table-column-selector';
 export * from './view-control-bar/view-control-bar';
 export * from './clearable-input/clearable-input';
diff --git a/web-console/src/components/menu-checkbox/menu-checkbox.tsx b/web-console/src/components/menu-checkbox/menu-checkbox.tsx
index 659a78c..f5ea252 100644
--- a/web-console/src/components/menu-checkbox/menu-checkbox.tsx
+++ b/web-console/src/components/menu-checkbox/menu-checkbox.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 
 import './menu-checkbox.scss';
 
-export class MenuCheckbox extends React.PureComponent<ICheckboxProps, {}> {
+export class MenuCheckbox extends React.PureComponent<ICheckboxProps> {
 
   render() {
     return <li className="menu-checkbox">
diff --git a/web-console/src/components/table-cell/table-cell.tsx b/web-console/src/components/table-cell/table-cell.tsx
index 036a4da..767bb1a 100644
--- a/web-console/src/components/table-cell/table-cell.tsx
+++ b/web-console/src/components/table-cell/table-cell.tsx
@@ -39,7 +39,7 @@ interface ShortParts {
   suffix: string;
 }
 
-export class TableCell extends React.PureComponent<NullTableCellProps, {}> {
+export class TableCell extends React.PureComponent<NullTableCellProps> {
   static MAX_CHARS_TO_SHOW = 50;
 
   static possiblyTruncate(str: string): React.ReactNode {
diff --git a/web-console/src/components/view-control-bar/view-control-bar.tsx b/web-console/src/components/view-control-bar/view-control-bar.tsx
index bcd3e23..247004c 100644
--- a/web-console/src/components/view-control-bar/view-control-bar.tsx
+++ b/web-console/src/components/view-control-bar/view-control-bar.tsx
@@ -24,7 +24,7 @@ export interface ViewControlBarProps {
   label: string;
 }
 
-export class ViewControlBar extends React.PureComponent<ViewControlBarProps, {}> {
+export class ViewControlBar extends React.PureComponent<ViewControlBarProps> {
   constructor(props: ViewControlBarProps) {
     super(props);
   }
diff --git a/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap b/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap
index 1383230..5e8951c 100644
--- a/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap
+++ b/web-console/src/dialogs/compaction-dialog/__snapshots__/compaction-dialog.spec.tsx.snap
@@ -352,7 +352,7 @@ exports[`compaction dialog matches snapshot 1`] = `
               class="bp3-form-content"
             >
               <div
-                class=" ace_editor ace-solarized-dark ace_dark"
+                class=" ace_editor ace-tm"
                 id="ace-editor"
                 style="width: 100%; height: 8vh;"
               >
@@ -543,7 +543,7 @@ exports[`compaction dialog matches snapshot 1`] = `
               class="bp3-form-content"
             >
               <div
-                class=" ace_editor ace-solarized-dark ace_dark"
+                class=" ace_editor ace-tm"
                 id="ace-editor"
                 style="width: 100%; height: 8vh;"
               >
diff --git a/web-console/src/dialogs/table-action-dialog/table-action-dialog.tsx b/web-console/src/dialogs/table-action-dialog/table-action-dialog.tsx
index 3719a07..11eab92 100644
--- a/web-console/src/dialogs/table-action-dialog/table-action-dialog.tsx
+++ b/web-console/src/dialogs/table-action-dialog/table-action-dialog.tsx
@@ -34,7 +34,7 @@ interface TableActionDialogProps extends IDialogProps {
   bottomButtons?: React.ReactNode;
 }
 
-export class TableActionDialog extends React.PureComponent<TableActionDialogProps, {}> {
+export class TableActionDialog extends React.PureComponent<TableActionDialogProps> {
   constructor(props: TableActionDialogProps) {
     super(props);
     this.state = {};
diff --git a/web-console/src/entry.ts b/web-console/src/entry.ts
index b18a145..cd35da7 100644
--- a/web-console/src/entry.ts
+++ b/web-console/src/entry.ts
@@ -16,6 +16,11 @@
  * limitations under the License.
  */
 
+import 'brace'; // Import Ace editor and all the sub components used in the app
+import 'brace/ext/language_tools';
+import 'brace/mode/hjson';
+import 'brace/mode/sql';
+import 'brace/theme/solarized_dark';
 import 'es6-shim/es6-shim';
 import 'es7-shim'; // Webpack with automatically pick browser.js which does the shim()
 import React from 'react';
diff --git a/web-console/src/utils/general.tsx b/web-console/src/utils/general.tsx
index 0d2dc39..438fc9d 100644
--- a/web-console/src/utils/general.tsx
+++ b/web-console/src/utils/general.tsx
@@ -113,6 +113,13 @@ export function sqlQueryCustomTableFilter(filter: Filter): string {
 
 // ----------------------------
 
+export function caseInsensitiveContains(testString: string, searchString: string): boolean {
+  if (!searchString) return true;
+  return testString.toLowerCase().includes(searchString.toLowerCase());
+}
+
+// ----------------------------
+
 export function countBy<T>(array: T[], fn: (x: T, index: number) => string = String): Record<string, number> {
   const counts: Record<string, number> = {};
   for (let i = 0; i < array.length; i++) {
@@ -177,6 +184,17 @@ export function getHeadProp(results: Record<string, any>[], prop: string): any {
 
 // ----------------------------
 
+export function memoize<T, U>(fn: (x: T) => U): (x: T) => U {
+  let lastInput: T;
+  let lastOutput: U;
+  return (x: T) => {
+    if (x === lastInput) return lastOutput;
+    lastInput = x;
+    lastOutput = fn(lastInput);
+    return lastOutput;
+  };
+}
+
 export function parseJson(json: string): any {
   try {
     return JSON.parse(json);
diff --git a/web-console/src/utils/ingestion-spec.tsx b/web-console/src/utils/ingestion-spec.tsx
index c7fc446..e9d92b5 100644
--- a/web-console/src/utils/ingestion-spec.tsx
+++ b/web-console/src/utils/ingestion-spec.tsx
@@ -26,6 +26,10 @@ import { ExternalLink } from '../components/external-link/external-link';
 import { TIMESTAMP_FORMAT_VALUES } from './druid-time';
 import { deepGet, deepSet } from './object-change';
 
+// These constants are used to make sure that they are not constantly recreated thrashing the pure components
+export const EMPTY_OBJECT: any = {};
+export const EMPTY_ARRAY: any[] = [];
+
 export interface IngestionSpec {
   type?: IngestionType;
   dataSchema: DataSchema;
@@ -61,7 +65,7 @@ function ingestionTypeToIoAndTuningConfigType(ingestionType: IngestionType): str
 }
 
 export function getIngestionComboType(spec: IngestionSpec): IngestionComboType | null {
-  const ioConfig = deepGet(spec, 'ioConfig') || {};
+  const ioConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
 
   switch (ioConfig.type) {
     case 'kafka':
@@ -70,7 +74,7 @@ export function getIngestionComboType(spec: IngestionSpec): IngestionComboType |
 
     case 'index':
     case 'index_parallel':
-      const firehose = deepGet(spec, 'ioConfig.firehose') || {};
+      const firehose = deepGet(spec, 'ioConfig.firehose') || EMPTY_OBJECT;
       switch (firehose.type) {
         case 'local':
         case 'http':
@@ -124,7 +128,7 @@ export function isParallel(spec: IngestionSpec): boolean {
 export type DimensionMode = 'specific' | 'auto-detect';
 
 export function getDimensionMode(spec: IngestionSpec): DimensionMode {
-  const dimensions = deepGet(spec, 'dataSchema.parser.parseSpec.dimensionsSpec.dimensions') || [];
+  const dimensions = deepGet(spec, 'dataSchema.parser.parseSpec.dimensionsSpec.dimensions') || EMPTY_ARRAY;
   return Array.isArray(dimensions) && dimensions.length === 0 ? 'auto-detect' : 'specific';
 }
 
@@ -1104,7 +1108,7 @@ export function guessDataSourceName(ioConfig: IoConfig): string | null {
           return filenameFromPath(firehose.baseDir);
 
         case 'static-s3':
-          return filenameFromPath((firehose.uris || [])[0] || (firehose.prefixes || [])[0]);
+          return filenameFromPath((firehose.uris || EMPTY_ARRAY)[0] || (firehose.prefixes || EMPTY_ARRAY)[0]);
 
         case 'http':
           return filenameFromPath(firehose.uris ? firehose.uris[0] : undefined);
@@ -1587,7 +1591,7 @@ export interface DimensionFiltersWithRest {
 }
 
 export function splitFilter(filter: DruidFilter | null): DimensionFiltersWithRest {
-  const inputAndFilters: DruidFilter[] = filter ? ((filter.type === 'and' && Array.isArray(filter.fields)) ? filter.fields : [filter]) : [];
+  const inputAndFilters: DruidFilter[] = filter ? ((filter.type === 'and' && Array.isArray(filter.fields)) ? filter.fields : [filter]) : EMPTY_ARRAY;
   const dimensionFilters: DruidFilter[] = inputAndFilters.filter(f => typeof f.dimension === 'string');
   const restFilters: DruidFilter[] = inputAndFilters.filter(f => typeof f.dimension !== 'string');
 
@@ -1599,7 +1603,7 @@ export function splitFilter(filter: DruidFilter | null): DimensionFiltersWithRes
 
 export function joinFilter(dimensionFiltersWithRest: DimensionFiltersWithRest): DruidFilter | null {
   const { dimensionFilters, restFilter } = dimensionFiltersWithRest;
-  let newFields = dimensionFilters || [];
+  let newFields = dimensionFilters || EMPTY_ARRAY;
   if (restFilter && restFilter.type) newFields = newFields.concat([restFilter]);
 
   if (!newFields.length) return null;
diff --git a/web-console/src/utils/sampler.ts b/web-console/src/utils/sampler.ts
index c20109a..1996bf3 100644
--- a/web-console/src/utils/sampler.ts
+++ b/web-console/src/utils/sampler.ts
@@ -260,7 +260,7 @@ export async function sampleForTimestamp(spec: IngestionSpec, sampleStrategy: Sa
       }
     },
     samplerConfig: Object.assign({}, BASE_SAMPLER_CONFIG, {
-      cacheKey
+      cacheKey: sampleColumns.cacheKey || cacheKey
     })
   };
 
diff --git a/web-console/src/views/load-data-view/filter-table/__snapshots__/filter-table.spec.tsx.snap b/web-console/src/views/load-data-view/filter-table/__snapshots__/filter-table.spec.tsx.snap
new file mode 100644
index 0000000..3d9f5c8
--- /dev/null
+++ b/web-console/src/views/load-data-view/filter-table/__snapshots__/filter-table.spec.tsx.snap
@@ -0,0 +1,1014 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`filter table matches snapshot 1`] = `
+<div
+  class="ReactTable filter-table -striped -highlight"
+>
+  <div
+    class="rt-table"
+    role="grid"
+  >
+    <div
+      class="rt-thead -header"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr"
+        role="row"
+      >
+        <div
+          class="rt-th rt-resizable-header"
+          role="columnheader"
+          style="flex: 100 0 auto; width: 100px;"
+          tabindex="-1"
+        >
+          <div
+            class="rt-resizable-header-content"
+          >
+            <div
+              class="clickable"
+            >
+              <div
+                class="column-name"
+              >
+                c1
+              </div>
+              <div
+                class="column-detail"
+              >
+                
+                 
+              </div>
+            </div>
+          </div>
+          <div
+            class="rt-resizer"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="rt-tbody"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            hello
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    class="-loading"
+  >
+    <div
+      class="-loading-inner"
+    >
+      Loading...
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/menu-checkbox/menu-checkbox.tsx b/web-console/src/views/load-data-view/filter-table/filter-table.scss
similarity index 73%
copy from web-console/src/components/menu-checkbox/menu-checkbox.tsx
copy to web-console/src/views/load-data-view/filter-table/filter-table.scss
index 659a78c..d57d317 100644
--- a/web-console/src/components/menu-checkbox/menu-checkbox.tsx
+++ b/web-console/src/views/load-data-view/filter-table/filter-table.scss
@@ -16,16 +16,16 @@
  * limitations under the License.
  */
 
-import { Checkbox, ICheckboxProps } from '@blueprintjs/core';
-import React from 'react';
-
-import './menu-checkbox.scss';
-
-export class MenuCheckbox extends React.PureComponent<ICheckboxProps, {}> {
+.filter-table {
+  .rt-th {
+    &.filtered {
+      background: rgba(201, 128, 22, 0.2);
+    }
+  }
 
-  render() {
-    return <li className="menu-checkbox">
-      <Checkbox {...this.props}/>
-    </li>;
+  .rt-td {
+    &.filtered {
+      background: rgba(201, 128, 22, 0.05);
+    }
   }
 }
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/load-data-view/filter-table/filter-table.spec.tsx
similarity index 65%
copy from web-console/src/components/sql-control/sql-control.spec.tsx
copy to web-console/src/views/load-data-view/filter-table/filter-table.spec.tsx
index 1ac07be..c959db4 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/views/load-data-view/filter-table/filter-table.spec.tsx
@@ -19,18 +19,30 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { SqlControl } from './sql-control';
+import { FilterTable } from './filter-table';
 
-describe('sql control', () => {
+describe('filter table', () => {
   it('matches snapshot', () => {
-    const sqlControl = <SqlControl
-      initSql={'test'}
-      onRun={(query, context, wrapQuery) => {}}
-      onExplain={(sqlQuery, context) => {}}
-      queryElapsed={2}
+    const sampleData = {
+      header: ['c1'],
+      rows: [
+        {
+          raw: `{"c1":"hello"}`,
+          parsed: { c1: 'hello' }
+        }
+      ]
+    };
+
+    const filterTable = <FilterTable
+      sampleData={sampleData}
+      columnFilter=""
+      dimensionFilters={[]}
+      selectedFilterIndex={-1}
+      onShowGlobalFilter={() => null}
+      onFilterSelect={() => null}
     />;
 
-    const { container } = render(sqlControl);
+    const { container } = render(filterTable);
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/views/load-data-view/filter-table/filter-table.tsx b/web-console/src/views/load-data-view/filter-table/filter-table.tsx
new file mode 100644
index 0000000..5e49d4a
--- /dev/null
+++ b/web-console/src/views/load-data-view/filter-table/filter-table.tsx
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import classNames from 'classnames';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import { TableCell } from '../../../components';
+import { caseInsensitiveContains, filterMap } from '../../../utils';
+import { DruidFilter, Transform } from '../../../utils/ingestion-spec';
+import { HeaderAndRows } from '../../../utils/sampler';
+
+import './filter-table.scss';
+
+export interface FilterTableProps extends React.Props<any> {
+  sampleData: HeaderAndRows;
+  columnFilter: string;
+  dimensionFilters: DruidFilter[];
+  selectedFilterIndex: number;
+  onShowGlobalFilter: () => void;
+  onFilterSelect: (filter: DruidFilter, index: number) => void;
+}
+
+export class FilterTable extends React.PureComponent<FilterTableProps> {
+  render() {
+    const { sampleData, columnFilter, dimensionFilters, selectedFilterIndex, onShowGlobalFilter, onFilterSelect } = this.props;
+
+    return <ReactTable
+      className="filter-table -striped -highlight"
+      data={sampleData.rows}
+      columns={filterMap(sampleData.header, (columnName, i) => {
+        if (!caseInsensitiveContains(columnName, columnFilter)) return null;
+        const timestamp = columnName === '__time';
+        const filterIndex = dimensionFilters.findIndex(f => f.dimension === columnName);
+        const filter = dimensionFilters[filterIndex];
+
+        const columnClassName = classNames({
+          filtered: filter,
+          selected: filter && filterIndex === selectedFilterIndex
+        });
+        return {
+          Header: (
+            <div
+              className={classNames('clickable')}
+              onClick={() => {
+                if (timestamp) {
+                  onShowGlobalFilter();
+                } else if (filter) {
+                  onFilterSelect(filter, filterIndex);
+                } else {
+                  onFilterSelect({ type: 'selector', dimension: columnName, value: '' }, -1);
+                }
+              }}
+            >
+              <div className="column-name">{columnName}</div>
+              <div className="column-detail">
+                {filter ? `(filtered)` : ''}&nbsp;
+              </div>
+            </div>
+          ),
+          headerClassName: columnClassName,
+          className: columnClassName,
+          id: String(i),
+          accessor: row => row.parsed ? row.parsed[columnName] : null,
+          Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
+        };
+      })}
+      defaultPageSize={50}
+      showPagination={false}
+      sortable={false}
+    />;
+  }
+}
diff --git a/web-console/src/views/load-data-view/load-data-view.scss b/web-console/src/views/load-data-view/load-data-view.scss
index 64ac83e..0e5a1b1 100644
--- a/web-console/src/views/load-data-view/load-data-view.scss
+++ b/web-console/src/views/load-data-view/load-data-view.scss
@@ -151,11 +151,6 @@
             border-radius: 2px;
           }
 
-          &.flattened,
-          &.transformed {
-            background: rgba(201, 128, 22, 0.2);
-          }
-
           .clickable {
             cursor: pointer;
           }
@@ -163,48 +158,12 @@
           &.timestamp {
             background: rgba(19, 129, 201, 0.5);
           }
-
-          &.dimension {
-            background: rgba(38, 170, 201, 0.5);
-
-            &.long { background: rgba(19, 129, 201, 0.5); }
-            &.float { background: rgba(25, 145, 201, 0.5); }
-          }
-
-          &.metric {
-            background: rgba(201, 191, 55, 0.5);
-          }
         }
 
         .rt-td {
-          &.flattened,
-          &.transformed {
-            background: rgba(201, 128, 22, 0.05);
-          }
-
           &.timestamp {
             background: rgba(19, 129, 201, 0.15);
           }
-
-          &.dimension {
-            background: rgba(38, 170, 201, 0.1);
-
-            &.long { background: rgba(19, 129, 201, 0.1); }
-            &.float { background: rgba(25, 145, 201, 0.1); }
-          }
-
-          &.metric {
-            background: rgba(201, 191, 55, 0.1);
-          }
-        }
-
-        .parse-detail {
-          padding: 10px;
-
-          .parse-error {
-            color: #9E2B0E;
-            margin-bottom: 12px;
-          }
         }
       }
     }
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 12ae636..b9aee95 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
@@ -29,7 +29,6 @@ import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
 import classNames from 'classnames';
 import React from 'react';
-import ReactTable from 'react-table';
 
 import { AutoForm, CenterMessage, ClearableInput, ExternalLink, JSONInput, Loader, TableCell } from '../../components';
 import { AsyncActionDialog } from '../../dialogs';
@@ -39,10 +38,9 @@ import {
   getDruidErrorMessage,
   localStorageGet,
   LocalStorageKeys,
-  localStorageSet, parseJson,
-  QueryState, sortWithPrefixSuffix
+  localStorageSet, memoize, parseJson,
+  QueryState
 } from '../../utils';
-import { escapeColumnName } from '../../utils/druid-expression';
 import { possibleDruidFormatForValues } from '../../utils/druid-time';
 import { updateSchemaWithSample } from '../../utils/druid-type';
 import {
@@ -50,15 +48,13 @@ import {
   DimensionMode,
   DimensionSpec,
   DimensionsSpec,
-  DruidFilter,
+  DruidFilter, EMPTY_ARRAY, EMPTY_OBJECT,
   fillDataSourceName,
   fillParser,
   FlattenField,
   getBlankSpec,
   getDimensionMode,
   getDimensionSpecFormFields,
-  getDimensionSpecName,
-  getDimensionSpecType,
   getEmptyTimestampSpec,
   getFilterFormFields,
   getFlattenFieldFormFields,
@@ -66,20 +62,17 @@ import {
   getIoConfigFormFields,
   getIoConfigTuningFormFields,
   getMetricSpecFormFields,
-  getMetricSpecName,
   getParseSpecFormFields,
   getPartitionRelatedTuningSpecFormFields,
   getRollup,
   getSpecType,
-  getTimestampSpecColumn,
   getTimestampSpecFormFields,
   getTransformFormFields,
   getTuningSpecFormFields,
   GranularitySpec,
   hasParallelAbility,
-  inflateDimensionSpec, IngestionComboType,
+  IngestionComboType,
   IngestionSpec,
-  IngestionType,
   IoConfig,
   isColumnTimestampSpec,
   isParallel,
@@ -100,7 +93,6 @@ import {
   getOverlordModules,
   HeaderAndRows,
   headerAndRowsFromSampleResponse,
-  SampleEntry,
   sampleForConnect,
   sampleForFilter,
   sampleForParser, sampleForSchema,
@@ -111,6 +103,12 @@ import {
 } from '../../utils/sampler';
 import { computeFlattenPathsForData } from '../../utils/spec-utils';
 
+import { FilterTable } from './filter-table/filter-table';
+import { ParseDataTable } from './parse-data-table/parse-data-table';
+import { ParseTimeTable } from './parse-time-table/parse-time-table';
+import { SchemaTable } from './schema-table/schema-table';
+import { TransformTable } from './transform-table/transform-table';
+
 import './load-data-view.scss';
 
 function showRawLine(line: string): string {
@@ -123,11 +121,6 @@ function showRawLine(line: string): string {
   return line;
 }
 
-function filterMatch(testString: string, searchString: string): boolean {
-  if (!searchString) return true;
-  return testString.toLowerCase().includes(searchString.toLowerCase());
-}
-
 function getTimestampSpec(headerAndRows: HeaderAndRows | null): TimestampSpec {
   if (!headerAndRows) return getEmptyTimestampSpec();
 
@@ -201,7 +194,10 @@ export interface LoadDataViewState {
   selectedFlattenField: FlattenField | null;
 
   // for timestamp
-  timestampQueryState: QueryState<HeaderAndRows>;
+  timestampQueryState: QueryState<{
+    headerAndRows: HeaderAndRows;
+    timestampSpec: TimestampSpec;
+  }>;
 
   // for transform
   transformQueryState: QueryState<HeaderAndRows>;
@@ -215,7 +211,11 @@ export interface LoadDataViewState {
   showGlobalFilter: boolean;
 
   // for schema
-  schemaQueryState: QueryState<HeaderAndRows>;
+  schemaQueryState: QueryState<{
+    headerAndRows: HeaderAndRows;
+    dimensionsSpec: DimensionsSpec;
+    metricsSpec: MetricSpec[];
+  }>;
   selectedDimensionSpecIndex: number;
   selectedDimensionSpec: DimensionSpec | null;
   selectedMetricSpecIndex: number;
@@ -517,7 +517,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   async queryForConnect(initRun = false) {
     const { spec, sampleStrategy } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
 
     let issue: string | undefined;
     if (issueWithIoConfig(ioConfig)) {
@@ -554,7 +554,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
   renderConnectStage() {
     const { spec, inputQueryState, sampleStrategy } = this.state;
     const specType = getSpecType(spec);
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
     const isBlank = !ioConfig.type;
 
     let mainFill: JSX.Element | string = '';
@@ -653,8 +653,8 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   async queryForParser(initRun = false) {
     const { spec, sampleStrategy, cacheKey } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const parser: Parser = deepGet(spec, 'dataSchema.parser') || EMPTY_OBJECT;
 
     let issue: string | null = null;
     if (issueWithIoConfig(ioConfig)) {
@@ -694,8 +694,8 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   renderParserStage() {
     const { spec, columnFilter, specialColumnsOnly, parserQueryState, selectedFlattenField } = this.state;
-    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || {};
-    const flattenFields: FlattenField[] = deepGet(spec, 'dataSchema.parser.parseSpec.flattenSpec.fields') || [];
+    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || EMPTY_OBJECT;
+    const flattenFields: FlattenField[] = deepGet(spec, 'dataSchema.parser.parseSpec.flattenSpec.fields') || EMPTY_ARRAY;
 
     const isBlank = !parseSpec.format;
     const canFlatten = parseSpec.format === 'json';
@@ -732,61 +732,13 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             />
           }
         </div>
-        <ReactTable
-          data={parserQueryState.data.rows}
-          columns={filterMap(parserQueryState.data.header, (columnName, i) => {
-            if (!filterMatch(columnName, columnFilter)) return null;
-            const flattenFieldIndex = flattenFields.findIndex(f => f.name === columnName);
-            if (flattenFieldIndex === -1 && specialColumnsOnly) return null;
-            const flattenField = flattenFields[flattenFieldIndex];
-            return {
-              Header: (
-                <div
-                  className={classNames({ clickable: flattenField })}
-                  onClick={() => {
-                    this.setState({
-                      selectedFlattenFieldIndex: flattenFieldIndex,
-                      selectedFlattenField: flattenField
-                    });
-                  }}
-                >
-                  <div className="column-name">{columnName}</div>
-                  <div className="column-detail">
-                    {flattenField ? `${flattenField.type}: ${flattenField.expr}` : ''}&nbsp;
-                  </div>
-                </div>
-              ),
-              id: String(i),
-              accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
-              Cell: row => {
-                if (row.original.unparseable) {
-                  return <TableCell unparseable/>;
-                }
-                return <TableCell value={row.value}/>;
-              },
-              headerClassName: classNames({
-                flattened: flattenField
-              })
-            };
-          })}
-          SubComponent={rowInfo => {
-            const { raw, error } = rowInfo.original;
-            const parsedJson: any = parseJson(raw);
-
-            if (!error && parsedJson && canFlatten) {
-              return <pre className="parse-detail">
-                {'Original row: ' + JSON.stringify(parsedJson, null, 2)}
-              </pre>;
-            } else {
-              return <div className="parse-detail">
-                {error && <div className="parse-error">{error}</div>}
-                <div>{'Original row: ' + rowInfo.original.raw}</div>
-              </div>;
-            }
-          }}
-          defaultPageSize={50}
-          showPagination={false}
-          sortable={false}
+        <ParseDataTable
+          sampleData={parserQueryState.data}
+          columnFilter={columnFilter}
+          canFlatten={canFlatten}
+          flattenedColumnsOnly={specialColumnsOnly}
+          flattenFields={flattenFields}
+          onFlattenFieldSelect={this.onFlattenFieldSelect}
         />
       </div>;
     }
@@ -859,9 +811,16 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     </>;
   }
 
+  private onFlattenFieldSelect = (field: FlattenField, index: number) => {
+    this.setState({
+      selectedFlattenFieldIndex: index,
+      selectedFlattenField: field
+    });
+  }
+
   renderFlattenControls() {
     const { spec, selectedFlattenField, selectedFlattenFieldIndex } = this.state;
-    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || {};
+    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || EMPTY_OBJECT;
     if (!parseSpecHasFlatten(parseSpec)) return null;
 
     const close = () => {
@@ -934,8 +893,9 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   async queryForTimestamp(initRun = false) {
     const { spec, sampleStrategy, cacheKey } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const parser: Parser = deepGet(spec, 'dataSchema.parser') || EMPTY_OBJECT;
+    const timestampSpec = deepGet(spec, 'dataSchema.parser.parseSpec.timestampSpec') || EMPTY_OBJECT;
 
     let issue: string | null = null;
     if (issueWithIoConfig(ioConfig)) {
@@ -968,16 +928,18 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     this.setState({
       cacheKey: sampleResponse.cacheKey,
       timestampQueryState: new QueryState({
-        data: headerAndRowsFromSampleResponse(sampleResponse)
+        data: {
+          headerAndRows: headerAndRowsFromSampleResponse(sampleResponse),
+          timestampSpec
+        }
       })
     });
   }
 
   renderTimestampStage() {
     const { spec, columnFilter, specialColumnsOnly, timestampQueryState } = this.state;
-    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || {};
-    const timestampSpec: TimestampSpec = deepGet(spec, 'dataSchema.parser.parseSpec.timestampSpec') || {};
-    const timestampSpecColumn = getTimestampSpecColumn(timestampSpec);
+    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || EMPTY_OBJECT;
+    const timestampSpec: TimestampSpec = deepGet(spec, 'dataSchema.parser.parseSpec.timestampSpec') || EMPTY_OBJECT;
     const timestampSpecFromColumn = isColumnTimestampSpec(timestampSpec);
 
     const isBlank = !parseSpec.format;
@@ -997,7 +959,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
       </CenterMessage>;
 
     } else if (timestampQueryState.data) {
-      const timestampData = timestampQueryState.data;
       mainFill = <div className="table-with-control">
         <div className="table-control">
           <ClearableInput
@@ -1011,61 +972,11 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             onChange={() => this.setState({ specialColumnsOnly: !specialColumnsOnly })}
           />
         </div>
-        <ReactTable
-          data={timestampData.rows}
-          columns={filterMap(timestampData.header.length ? timestampData.header : ['__error__'], (columnName, i) => {
-            const timestamp = columnName === '__time';
-            if (!timestamp && !filterMatch(columnName, columnFilter)) return null;
-            const selected = timestampSpec.column === columnName;
-            const possibleFormat = timestamp ? null : possibleDruidFormatForValues(filterMap(timestampData.rows, d => d.parsed ? d.parsed[columnName] : null));
-            if (specialColumnsOnly && !timestamp && !possibleFormat) return null;
-
-            const columnClassName = classNames({
-              timestamp,
-              selected
-            });
-            return {
-              Header: (
-                <div
-                  className={classNames({ clickable: !timestamp })}
-                  onClick={timestamp ? undefined : () => {
-                    const newTimestampSpec = {
-                      column: columnName,
-                      format: possibleFormat || '!!! Could not auto detect a format !!!'
-                    };
-                    this.updateSpec(deepSet(spec, 'dataSchema.parser.parseSpec.timestampSpec', newTimestampSpec));
-                  }}
-                >
-                  <div className="column-name">{columnName}</div>
-                  <div className="column-detail">
-                    {
-                      timestamp ?
-                        (timestampSpecFromColumn ? `from: '${timestampSpecColumn}'` : `mv: ${timestampSpec.missingValue}`) :
-                        (possibleFormat || '')
-                    }&nbsp;
-                  </div>
-                </div>
-              ),
-              headerClassName: columnClassName,
-              className: columnClassName,
-              id: String(i),
-              accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
-              Cell: row => {
-                if (columnName === '__error__') {
-                  return <TableCell value={row.original.error}/>;
-                }
-                if (row.original.unparseable) {
-                  return <TableCell unparseable/>;
-                }
-                return <TableCell value={row.value} timestamp={timestamp}/>;
-              },
-              minWidth: timestamp ? 200 : 100,
-              resizable: !timestamp
-            };
-          })}
-          defaultPageSize={50}
-          showPagination={false}
-          sortable={false}
+        <ParseTimeTable
+          sampleBundle={timestampQueryState.data}
+          columnFilter={columnFilter}
+          possibleTimestampColumnsOnly={specialColumnsOnly}
+          onTimestampColumnSelect={this.onTimestampColumnSelect}
         />
       </div>;
     }
@@ -1131,12 +1042,17 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     </>;
   }
 
+  private onTimestampColumnSelect = (newTimestampSpec: TimestampSpec) => {
+    const { spec } = this.state;
+    this.updateSpec(deepSet(spec, 'dataSchema.parser.parseSpec.timestampSpec', newTimestampSpec));
+  }
+
   // ==================================================================
 
   async queryForTransform(initRun = false) {
     const { spec, sampleStrategy, cacheKey } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const parser: Parser = deepGet(spec, 'dataSchema.parser') || EMPTY_OBJECT;
 
     let issue: string | null = null;
     if (issueWithIoConfig(ioConfig)) {
@@ -1176,7 +1092,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   renderTransformStage() {
     const { spec, columnFilter, specialColumnsOnly, transformQueryState, selectedTransformIndex } = this.state;
-    const transforms: Transform[] = deepGet(spec, 'dataSchema.transformSpec.transforms') || [];
+    const transforms: Transform[] = deepGet(spec, 'dataSchema.transformSpec.transforms') || EMPTY_ARRAY;
 
     let mainFill: JSX.Element | string = '';
     if (transformQueryState.isInit()) {
@@ -1207,57 +1123,13 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             disabled={!transforms.length}
           />
         </div>
-        <ReactTable
-          data={transformQueryState.data.rows}
-          columns={filterMap(transformQueryState.data.header, (columnName, i) => {
-            if (!filterMatch(columnName, columnFilter)) return null;
-            const timestamp = columnName === '__time';
-            const transformIndex = transforms.findIndex(f => f.name === columnName);
-            if (transformIndex === -1 && specialColumnsOnly) return null;
-            const transform = transforms[transformIndex];
-
-            const columnClassName = classNames({
-              transformed: transform,
-              selected: transform && transformIndex === selectedTransformIndex
-            });
-            return {
-              Header: (
-                <div
-                  className={classNames('clickable')}
-                  onClick={() => {
-                    if (transform) {
-                      this.setState({
-                        selectedTransformIndex: transformIndex,
-                        selectedTransform: transform
-                      });
-                    } else {
-                      this.setState({
-                        selectedTransformIndex: -1,
-                        selectedTransform: {
-                          type: 'expression',
-                          name: columnName,
-                          expression: escapeColumnName(columnName)
-                        }
-                      });
-                    }
-                  }}
-                >
-                  <div className="column-name">{columnName}</div>
-                  <div className="column-detail">
-                    {transform ? `= ${transform.expression}` : ''}&nbsp;
-                  </div>
-                </div>
-              ),
-              headerClassName: columnClassName,
-              className: columnClassName,
-              id: String(i),
-              accessor: row => row.parsed ? row.parsed[columnName] : null,
-              Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
-            };
-          })}
-          defaultPageSize={50}
-          showPagination={false}
-          sortable={false}
+        <TransformTable
+          sampleData={transformQueryState.data}
+          columnFilter={columnFilter}
+          transformedColumnsOnly={specialColumnsOnly}
+          transforms={transforms}
+          selectedTransformIndex={selectedTransformIndex}
+          onTransformSelect={this.onTransformSelect}
         />
       </div>;
     }
@@ -1308,6 +1180,13 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     </>;
   }
 
+  private onTransformSelect = (transform: Transform, index: number) => {
+    this.setState({
+      selectedTransformIndex: index,
+      selectedTransform: transform
+    });
+  }
+
   renderTransformControls() {
     const { spec, selectedTransform, selectedTransformIndex } = this.state;
 
@@ -1376,8 +1255,8 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   async queryForFilter(initRun = false) {
     const { spec, sampleStrategy, cacheKey } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const parser: Parser = deepGet(spec, 'dataSchema.parser') || EMPTY_OBJECT;
 
     let issue: string | null = null;
     if (issueWithIoConfig(ioConfig)) {
@@ -1415,10 +1294,15 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     });
   }
 
+  private getMemoizedDimensionFiltersFromSpec = memoize<IngestionSpec, DruidFilter[]>((spec) => {
+    const { dimensionFilters } = splitFilter(deepGet(spec, 'dataSchema.transformSpec.filter'));
+    return dimensionFilters;
+  });
+
   renderFilterStage() {
     const { spec, columnFilter, filterQueryState, selectedFilter, selectedFilterIndex, showGlobalFilter } = this.state;
-    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || {};
-    const { dimensionFilters } = splitFilter(deepGet(spec, 'dataSchema.transformSpec.filter'));
+    const parseSpec: ParseSpec = deepGet(spec, 'dataSchema.parser.parseSpec') || EMPTY_OBJECT;
+    const dimensionFilters = this.getMemoizedDimensionFiltersFromSpec(spec);
 
     const isBlank = !parseSpec.format;
 
@@ -1445,56 +1329,13 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             placeholder="Search columns"
           />
         </div>
-        <ReactTable
-          data={filterQueryState.data.rows}
-          columns={filterMap(filterQueryState.data.header, (columnName, i) => {
-            if (!filterMatch(columnName, columnFilter)) return null;
-            const timestamp = columnName === '__time';
-            const filterIndex = dimensionFilters.findIndex(f => f.dimension === columnName);
-            const filter = dimensionFilters[filterIndex];
-
-            const columnClassName = classNames({
-              filtered: filter,
-              selected: filter && filterIndex === selectedFilterIndex
-            });
-            return {
-              Header: (
-                <div
-                  className={classNames('clickable')}
-                  onClick={() => {
-                    if (timestamp) {
-                      this.setState({
-                        showGlobalFilter: true
-                      });
-                    } else if (filter) {
-                      this.setState({
-                        selectedFilterIndex: filterIndex,
-                        selectedFilter: filter
-                      });
-                    } else {
-                      this.setState({
-                        selectedFilterIndex: -1,
-                        selectedFilter: { type: 'selector', dimension: columnName, value: '' }
-                      });
-                    }
-                  }}
-                >
-                  <div className="column-name">{columnName}</div>
-                  <div className="column-detail">
-                    {filter ? `(filtered)` : ''}&nbsp;
-                  </div>
-                </div>
-              ),
-              headerClassName: columnClassName,
-              className: columnClassName,
-              id: String(i),
-              accessor: row => row.parsed ? row.parsed[columnName] : null,
-              Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
-            };
-          })}
-          defaultPageSize={50}
-          showPagination={false}
-          sortable={false}
+        <FilterTable
+          sampleData={filterQueryState.data}
+          columnFilter={columnFilter}
+          dimensionFilters={dimensionFilters}
+          selectedFilterIndex={selectedFilterIndex}
+          onShowGlobalFilter={this.onShowGlobalFilter}
+          onFilterSelect={this.onFilterSelect}
         />
       </div>;
     }
@@ -1528,6 +1369,17 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     </>;
   }
 
+  private onShowGlobalFilter = () => {
+    this.setState({ showGlobalFilter: true });
+  }
+
+  private onFilterSelect = (filter: DruidFilter, index: number) => {
+    this.setState({
+      selectedFilterIndex: index,
+      selectedFilter: filter
+    });
+  }
+
   renderColumnFilterControls() {
     const { spec, selectedFilter, selectedFilterIndex } = this.state;
 
@@ -1658,8 +1510,10 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   async queryForSchema(initRun = false) {
     const { spec, sampleStrategy, cacheKey } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const parser: Parser = deepGet(spec, 'dataSchema.parser') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const parser: Parser = deepGet(spec, 'dataSchema.parser') || EMPTY_OBJECT;
+    const metricsSpec: MetricSpec[] = deepGet(spec, 'dataSchema.metricsSpec') || EMPTY_ARRAY;
+    const dimensionsSpec: DimensionsSpec = deepGet(spec, 'dataSchema.parser.parseSpec.dimensionsSpec') || EMPTY_OBJECT;
 
     let issue: string | null = null;
     if (issueWithIoConfig(ioConfig)) {
@@ -1692,15 +1546,17 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     this.setState({
       cacheKey: sampleResponse.cacheKey,
       schemaQueryState: new QueryState({
-        data: headerAndRowsFromSampleResponse(sampleResponse)
+        data: {
+          headerAndRows: headerAndRowsFromSampleResponse(sampleResponse),
+          dimensionsSpec,
+          metricsSpec
+        }
       })
     });
   }
 
   renderSchemaStage() {
     const { spec, columnFilter, schemaQueryState, selectedDimensionSpec, selectedDimensionSpecIndex, selectedMetricSpec, selectedMetricSpecIndex } = this.state;
-    const metricsSpec: MetricSpec[] = deepGet(spec, 'dataSchema.metricsSpec') || [];
-    const dimensionsSpec: DimensionsSpec = deepGet(spec, 'dataSchema.parser.parseSpec.dimensionsSpec') || {};
     const rollup: boolean = Boolean(deepGet(spec, 'dataSchema.granularitySpec.rollup'));
     const somethingSelected = Boolean(selectedDimensionSpec || selectedMetricSpec);
     const dimensionMode = getDimensionMode(spec);
@@ -1720,7 +1576,6 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
       </CenterMessage>;
 
     } else if (schemaQueryState.data) {
-      const dimensionMetricSortedHeader = sortWithPrefixSuffix(schemaQueryState.data.header, ['__time'], metricsSpec.map(getMetricSpecName));
       mainFill = <div className="table-with-control">
         <div className="table-control">
           <ClearableInput
@@ -1729,93 +1584,12 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
             placeholder="Search columns"
           />
         </div>
-        <ReactTable
-          data={schemaQueryState.data.rows}
-          columns={filterMap(dimensionMetricSortedHeader, (columnName, i) => {
-            if (!filterMatch(columnName, columnFilter)) return null;
-
-            const metricSpecIndex = metricsSpec.findIndex(m => getMetricSpecName(m) === columnName);
-            const metricSpec = metricsSpec[metricSpecIndex];
-
-            if (metricSpec) {
-              const columnClassName = classNames('metric', {
-                selected: metricSpec && metricSpecIndex === selectedMetricSpecIndex
-              });
-              return {
-                Header: (
-                  <div
-                    className="clickable"
-                    onClick={() => {
-                      this.setState({
-                        selectedMetricSpecIndex: metricSpecIndex,
-                        selectedMetricSpec: metricSpec,
-                        selectedDimensionSpecIndex: -1,
-                        selectedDimensionSpec: null
-                      });
-                    }}
-                  >
-                    <div className="column-name">{columnName}</div>
-                    <div className="column-detail">
-                      {metricSpec.type}&nbsp;
-                    </div>
-                  </div>
-                ),
-                headerClassName: columnClassName,
-                className: columnClassName,
-                id: String(i),
-                accessor: row => row.parsed ? row.parsed[columnName] : null,
-                Cell: row => <TableCell value={row.value}/>
-              };
-            } else {
-              const timestamp = columnName === '__time';
-              const dimensionSpecIndex = dimensionsSpec.dimensions ? dimensionsSpec.dimensions.findIndex(d => getDimensionSpecName(d) === columnName) : -1;
-              const dimensionSpec = dimensionsSpec.dimensions ? dimensionsSpec.dimensions[dimensionSpecIndex] : null;
-              const dimensionSpecType = dimensionSpec ? getDimensionSpecType(dimensionSpec) : null;
-
-              const columnClassName = classNames(timestamp ? 'timestamp' : 'dimension', dimensionSpecType || 'string', {
-                selected: dimensionSpec && dimensionSpecIndex === selectedDimensionSpecIndex
-              });
-              return {
-                Header: (
-                  <div
-                    className="clickable"
-                    onClick={() => {
-                      if (timestamp) {
-                        this.setState({
-                          selectedDimensionSpecIndex: -1,
-                          selectedDimensionSpec: null,
-                          selectedMetricSpecIndex: -1,
-                          selectedMetricSpec: null
-                        });
-                        return;
-                      }
-
-                      if (!dimensionSpec) return;
-                      this.setState({
-                        selectedDimensionSpecIndex: dimensionSpecIndex,
-                        selectedDimensionSpec: inflateDimensionSpec(dimensionSpec),
-                        selectedMetricSpecIndex: -1,
-                        selectedMetricSpec: null
-                      });
-                    }}
-                  >
-                    <div className="column-name">{columnName}</div>
-                    <div className="column-detail">
-                      {timestamp ? 'long (time column)' : (dimensionSpecType || 'string (auto)')}&nbsp;
-                    </div>
-                  </div>
-                ),
-                headerClassName: columnClassName,
-                className: columnClassName,
-                id: String(i),
-                accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
-                Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
-              };
-            }
-          })}
-          defaultPageSize={50}
-          showPagination={false}
-          sortable={false}
+        <SchemaTable
+          sampleBundle={schemaQueryState.data}
+          columnFilter={columnFilter}
+          selectedDimensionSpecIndex={selectedDimensionSpecIndex}
+          selectedMetricSpecIndex={selectedMetricSpecIndex}
+          onDimensionOrMetricSelect={this.onDimensionOrMetricSelect}
         />
       </div>;
     }
@@ -1926,6 +1700,20 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
     </>;
   }
 
+  private onDimensionOrMetricSelect = (
+    selectedDimensionSpec: DimensionSpec | null,
+    selectedDimensionSpecIndex: number,
+    selectedMetricSpec: MetricSpec | null,
+    selectedMetricSpecIndex: number
+  ) => {
+    this.setState({
+      selectedDimensionSpec,
+      selectedDimensionSpecIndex,
+      selectedMetricSpec,
+      selectedMetricSpecIndex
+    });
+  }
+
   renderChangeRollupAction() {
     const { newRollup, spec, sampleStrategy, cacheKey } = this.state;
     if (newRollup === null) return;
@@ -2025,7 +1813,7 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
               icon={IconNames.TRASH}
               intent={Intent.DANGER}
               onClick={() => {
-                const curDimensions = deepGet(spec, `dataSchema.parser.parseSpec.dimensionsSpec.dimensions`) || [];
+                const curDimensions = deepGet(spec, `dataSchema.parser.parseSpec.dimensionsSpec.dimensions`) || EMPTY_ARRAY;
                 if (curDimensions.length <= 1) return; // Guard against removing the last dimension, ToDo: some better feedback here would be good
 
                 this.updateSpec(deepDelete(spec, `dataSchema.parser.parseSpec.dimensionsSpec.dimensions.${selectedDimensionSpecIndex}`));
@@ -2128,8 +1916,8 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   renderPartitionStage() {
     const { spec } = this.state;
-    const tuningConfig: TuningConfig = deepGet(spec, 'tuningConfig') || {};
-    const granularitySpec: GranularitySpec = deepGet(spec, 'dataSchema.granularitySpec') || {};
+    const tuningConfig: TuningConfig = deepGet(spec, 'tuningConfig') || EMPTY_OBJECT;
+    const granularitySpec: GranularitySpec = deepGet(spec, 'dataSchema.granularitySpec') || EMPTY_OBJECT;
 
     return <>
       <div className="main">
@@ -2187,8 +1975,8 @@ export class LoadDataView extends React.PureComponent<LoadDataViewProps, LoadDat
 
   renderTuningStage() {
     const { spec } = this.state;
-    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || {};
-    const tuningConfig: TuningConfig = deepGet(spec, 'tuningConfig') || {};
+    const ioConfig: IoConfig = deepGet(spec, 'ioConfig') || EMPTY_OBJECT;
+    const tuningConfig: TuningConfig = deepGet(spec, 'tuningConfig') || EMPTY_OBJECT;
 
     const ingestionComboType = getIngestionComboType(spec);
     const inputTuningFields = ingestionComboType ? getIoConfigTuningFormFields(ingestionComboType) : null;
diff --git a/web-console/src/views/load-data-view/parse-data-table/__snapshots__/parse-data-table.spec.tsx.snap b/web-console/src/views/load-data-view/parse-data-table/__snapshots__/parse-data-table.spec.tsx.snap
new file mode 100644
index 0000000..8a047e5
--- /dev/null
+++ b/web-console/src/views/load-data-view/parse-data-table/__snapshots__/parse-data-table.spec.tsx.snap
@@ -0,0 +1,1476 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parse data table matches snapshot 1`] = `
+<div
+  class="ReactTable parse-data-table -striped -highlight"
+>
+  <div
+    class="rt-table"
+    role="grid"
+  >
+    <div
+      class="rt-thead -header"
+      style="min-width: 135px;"
+    >
+      <div
+        class="rt-tr"
+        role="row"
+      >
+        <div
+          class="rt-th"
+          role="columnheader"
+          style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          tabindex="-1"
+        >
+          <div
+            class=""
+          />
+        </div>
+        <div
+          class="rt-th rt-resizable-header"
+          role="columnheader"
+          style="flex: 100 0 auto; width: 100px;"
+          tabindex="-1"
+        >
+          <div
+            class="rt-resizable-header-content"
+          >
+            <div
+              class=""
+            >
+              <div
+                class="column-name"
+              >
+                c1
+              </div>
+              <div
+                class="column-detail"
+              >
+                
+                 
+              </div>
+            </div>
+          </div>
+          <div
+            class="rt-resizer"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="rt-tbody"
+      style="min-width: 135px;"
+    >
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -odd"
+          role="row"
+        >
+          <div
+            class="rt-td rt-expandable"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <div
+              class="rt-expander"
+            >
+              •
+            </div>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            hello
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 35 0 auto; width: 35px; max-width: 35px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    class="-loading"
+  >
+    <div
+      class="-loading-inner"
+    >
+      Loading...
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/menu-checkbox/menu-checkbox.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.scss
similarity index 73%
copy from web-console/src/components/menu-checkbox/menu-checkbox.tsx
copy to web-console/src/views/load-data-view/parse-data-table/parse-data-table.scss
index 659a78c..306b3d3 100644
--- a/web-console/src/components/menu-checkbox/menu-checkbox.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.scss
@@ -16,16 +16,25 @@
  * limitations under the License.
  */
 
-import { Checkbox, ICheckboxProps } from '@blueprintjs/core';
-import React from 'react';
+.parse-data-table {
+  .rt-th {
+    &.flattened {
+      background: rgba(201, 128, 22, 0.2);
+    }
+  }
 
-import './menu-checkbox.scss';
+  .rt-td {
+    &.flattened {
+      background: rgba(201, 128, 22, 0.05);
+    }
+  }
 
-export class MenuCheckbox extends React.PureComponent<ICheckboxProps, {}> {
+  .parse-detail {
+    padding: 10px;
 
-  render() {
-    return <li className="menu-checkbox">
-      <Checkbox {...this.props}/>
-    </li>;
+    .parse-error {
+      color: #9E2B0E;
+      margin-bottom: 12px;
+    }
   }
 }
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
similarity index 65%
copy from web-console/src/components/sql-control/sql-control.spec.tsx
copy to web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
index 1ac07be..6a83e73 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.spec.tsx
@@ -19,18 +19,30 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { SqlControl } from './sql-control';
+import { ParseDataTable } from './parse-data-table';
 
-describe('sql control', () => {
+describe('parse data table', () => {
   it('matches snapshot', () => {
-    const sqlControl = <SqlControl
-      initSql={'test'}
-      onRun={(query, context, wrapQuery) => {}}
-      onExplain={(sqlQuery, context) => {}}
-      queryElapsed={2}
+    const sampleData = {
+      header: ['c1'],
+      rows: [
+        {
+          raw: `{"c1":"hello"}`,
+          parsed: { c1: 'hello' }
+        }
+      ]
+    };
+
+    const parseDataTable = <ParseDataTable
+      sampleData={sampleData}
+      columnFilter=""
+      canFlatten={false}
+      flattenedColumnsOnly={false}
+      flattenFields={[]}
+      onFlattenFieldSelect={() => null}
     />;
 
-    const { container } = render(sqlControl);
+    const { container } = render(parseDataTable);
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
new file mode 100644
index 0000000..c58f607
--- /dev/null
+++ b/web-console/src/views/load-data-view/parse-data-table/parse-data-table.tsx
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import classNames from 'classnames';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import { TableCell } from '../../../components';
+import { caseInsensitiveContains, filterMap, parseJson } from '../../../utils';
+import { FlattenField } from '../../../utils/ingestion-spec';
+import { HeaderAndRows, SampleEntry } from '../../../utils/sampler';
+
+import './parse-data-table.scss';
+
+export interface ParseDataTableProps extends React.Props<any> {
+  sampleData: HeaderAndRows;
+  columnFilter: string;
+  canFlatten: boolean;
+  flattenedColumnsOnly: boolean;
+  flattenFields: FlattenField[];
+  onFlattenFieldSelect: (field: FlattenField, index: number) => void;
+}
+
+export class ParseDataTable extends React.PureComponent<ParseDataTableProps> {
+  render() {
+    const { sampleData, columnFilter, canFlatten, flattenedColumnsOnly, flattenFields, onFlattenFieldSelect } = this.props;
+
+    return <ReactTable
+      className="parse-data-table -striped -highlight"
+      data={sampleData.rows}
+      columns={filterMap(sampleData.header, (columnName, i) => {
+        if (!caseInsensitiveContains(columnName, columnFilter)) return null;
+        const flattenFieldIndex = flattenFields.findIndex(f => f.name === columnName);
+        if (flattenFieldIndex === -1 && flattenedColumnsOnly) return null;
+        const flattenField = flattenFields[flattenFieldIndex];
+        return {
+          Header: (
+            <div
+              className={classNames({ clickable: flattenField })}
+              onClick={() => {
+                if (!flattenField) return;
+                onFlattenFieldSelect(flattenField, flattenFieldIndex);
+              }}
+            >
+              <div className="column-name">{columnName}</div>
+              <div className="column-detail">
+                {flattenField ? `${flattenField.type}: ${flattenField.expr}` : ''}&nbsp;
+              </div>
+            </div>
+          ),
+          id: String(i),
+          accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
+          Cell: row => {
+            if (row.original.unparseable) {
+              return <TableCell unparseable/>;
+            }
+            return <TableCell value={row.value}/>;
+          },
+          headerClassName: classNames({
+            flattened: flattenField
+          })
+        };
+      })}
+      SubComponent={rowInfo => {
+        const { raw, error } = rowInfo.original;
+        const parsedJson: any = parseJson(raw);
+
+        if (!error && parsedJson && canFlatten) {
+          return <pre className="parse-detail">
+            {'Original row: ' + JSON.stringify(parsedJson, null, 2)}
+          </pre>;
+        } else {
+          return <div className="parse-detail">
+            {error && <div className="parse-error">{error}</div>}
+            <div>{'Original row: ' + rowInfo.original.raw}</div>
+          </div>;
+        }
+      }}
+      defaultPageSize={50}
+      showPagination={false}
+      sortable={false}
+    />;
+  }
+}
diff --git a/web-console/src/views/load-data-view/parse-time-table/__snapshots__/parse-time-table.spec.tsx.snap b/web-console/src/views/load-data-view/parse-time-table/__snapshots__/parse-time-table.spec.tsx.snap
new file mode 100644
index 0000000..8809a06
--- /dev/null
+++ b/web-console/src/views/load-data-view/parse-time-table/__snapshots__/parse-time-table.spec.tsx.snap
@@ -0,0 +1,1014 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`parse time table matches snapshot 1`] = `
+<div
+  class="ReactTable parse-time-table -striped -highlight"
+>
+  <div
+    class="rt-table"
+    role="grid"
+  >
+    <div
+      class="rt-thead -header"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr"
+        role="row"
+      >
+        <div
+          class="rt-th rt-resizable-header"
+          role="columnheader"
+          style="flex: 100 0 auto; width: 100px;"
+          tabindex="-1"
+        >
+          <div
+            class="rt-resizable-header-content"
+          >
+            <div
+              class="clickable"
+            >
+              <div
+                class="column-name"
+              >
+                c1
+              </div>
+              <div
+                class="column-detail"
+              >
+                
+                 
+              </div>
+            </div>
+          </div>
+          <div
+            class="rt-resizer"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="rt-tbody"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            hello
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    class="-loading"
+  >
+    <div
+      class="-loading-inner"
+    >
+      Loading...
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/menu-checkbox/menu-checkbox.tsx b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.scss
similarity index 72%
copy from web-console/src/components/menu-checkbox/menu-checkbox.tsx
copy to web-console/src/views/load-data-view/parse-time-table/parse-time-table.scss
index 659a78c..a107a17 100644
--- a/web-console/src/components/menu-checkbox/menu-checkbox.tsx
+++ b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.scss
@@ -16,16 +16,6 @@
  * limitations under the License.
  */
 
-import { Checkbox, ICheckboxProps } from '@blueprintjs/core';
-import React from 'react';
+.parse-time-table {
 
-import './menu-checkbox.scss';
-
-export class MenuCheckbox extends React.PureComponent<ICheckboxProps, {}> {
-
-  render() {
-    return <li className="menu-checkbox">
-      <Checkbox {...this.props}/>
-    </li>;
-  }
 }
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.spec.tsx
similarity index 60%
copy from web-console/src/components/sql-control/sql-control.spec.tsx
copy to web-console/src/views/load-data-view/parse-time-table/parse-time-table.spec.tsx
index 1ac07be..ce0be3d 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.spec.tsx
@@ -19,18 +19,33 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { SqlControl } from './sql-control';
+import { getEmptyTimestampSpec } from '../../../utils/ingestion-spec';
 
-describe('sql control', () => {
+import { ParseTimeTable } from './parse-time-table';
+
+describe('parse time table', () => {
   it('matches snapshot', () => {
-    const sqlControl = <SqlControl
-      initSql={'test'}
-      onRun={(query, context, wrapQuery) => {}}
-      onExplain={(sqlQuery, context) => {}}
-      queryElapsed={2}
+    const sampleData = {
+      header: ['c1'],
+      rows: [
+        {
+          raw: `{"c1":"hello"}`,
+          parsed: { c1: 'hello' }
+        }
+      ]
+    };
+
+    const parseTimeTable = <ParseTimeTable
+      sampleBundle={{
+        headerAndRows: sampleData,
+        timestampSpec: getEmptyTimestampSpec()
+      }}
+      columnFilter=""
+      possibleTimestampColumnsOnly={false}
+      onTimestampColumnSelect={() => null}
     />;
 
-    const { container } = render(sqlControl);
+    const { container } = render(parseTimeTable);
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/views/load-data-view/parse-time-table/parse-time-table.tsx b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.tsx
new file mode 100644
index 0000000..b6f1a15
--- /dev/null
+++ b/web-console/src/views/load-data-view/parse-time-table/parse-time-table.tsx
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import classNames from 'classnames';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import { TableCell } from '../../../components';
+import { caseInsensitiveContains, filterMap } from '../../../utils';
+import { possibleDruidFormatForValues } from '../../../utils/druid-time';
+import { getTimestampSpecColumn, isColumnTimestampSpec, TimestampSpec } from '../../../utils/ingestion-spec';
+import { HeaderAndRows, SampleEntry } from '../../../utils/sampler';
+
+import './parse-time-table.scss';
+
+export interface ParseTimeTableProps extends React.Props<any> {
+  sampleBundle: {
+    headerAndRows: HeaderAndRows;
+    timestampSpec: TimestampSpec;
+  };
+  columnFilter: string;
+  possibleTimestampColumnsOnly: boolean;
+  onTimestampColumnSelect: (newTimestampSpec: TimestampSpec) => void;
+}
+
+export class ParseTimeTable extends React.PureComponent<ParseTimeTableProps> {
+  render() {
+    const { sampleBundle, columnFilter, possibleTimestampColumnsOnly, onTimestampColumnSelect } = this.props;
+    const { headerAndRows, timestampSpec } = sampleBundle;
+    const timestampSpecColumn = getTimestampSpecColumn(timestampSpec);
+    const timestampSpecFromColumn = isColumnTimestampSpec(timestampSpec);
+
+    return <ReactTable
+      className="parse-time-table -striped -highlight"
+      data={headerAndRows.rows}
+      columns={filterMap(headerAndRows.header.length ? headerAndRows.header : ['__error__'], (columnName, i) => {
+        const timestamp = columnName === '__time';
+        if (!timestamp && !caseInsensitiveContains(columnName, columnFilter)) return null;
+        const selected = timestampSpec.column === columnName;
+        const possibleFormat = timestamp ? null : possibleDruidFormatForValues(filterMap(headerAndRows.rows, d => d.parsed ? d.parsed[columnName] : null));
+        if (possibleTimestampColumnsOnly && !timestamp && !possibleFormat) return null;
+
+        const columnClassName = classNames({
+          timestamp,
+          selected
+        });
+        return {
+          Header: (
+            <div
+              className={classNames({ clickable: !timestamp })}
+              onClick={timestamp ? undefined : () => {
+                onTimestampColumnSelect({
+                  column: columnName,
+                  format: possibleFormat || '!!! Could not auto detect a format !!!'
+                });
+              }}
+            >
+              <div className="column-name">{columnName}</div>
+              <div className="column-detail">
+                {
+                  timestamp ?
+                    (timestampSpecFromColumn ? `from: '${timestampSpecColumn}'` : `mv: ${timestampSpec.missingValue}`) :
+                    (possibleFormat || '')
+                }&nbsp;
+              </div>
+            </div>
+          ),
+          headerClassName: columnClassName,
+          className: columnClassName,
+          id: String(i),
+          accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
+          Cell: row => {
+            if (columnName === '__error__') {
+              return <TableCell value={row.original.error}/>;
+            }
+            if (row.original.unparseable) {
+              return <TableCell unparseable/>;
+            }
+            return <TableCell value={row.value} timestamp={timestamp}/>;
+          },
+          minWidth: timestamp ? 200 : 100,
+          resizable: !timestamp
+        };
+      })}
+      defaultPageSize={50}
+      showPagination={false}
+      sortable={false}
+    />;
+  }
+}
diff --git a/web-console/src/views/load-data-view/schema-table/__snapshots__/schema-table.spec.tsx.snap b/web-console/src/views/load-data-view/schema-table/__snapshots__/schema-table.spec.tsx.snap
new file mode 100644
index 0000000..f5f1e2e
--- /dev/null
+++ b/web-console/src/views/load-data-view/schema-table/__snapshots__/schema-table.spec.tsx.snap
@@ -0,0 +1,1014 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`schema table matches snapshot 1`] = `
+<div
+  class="ReactTable schema-table -striped -highlight"
+>
+  <div
+    class="rt-table"
+    role="grid"
+  >
+    <div
+      class="rt-thead -header"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr"
+        role="row"
+      >
+        <div
+          class="rt-th dimension string rt-resizable-header"
+          role="columnheader"
+          style="flex: 100 0 auto; width: 100px;"
+          tabindex="-1"
+        >
+          <div
+            class="rt-resizable-header-content"
+          >
+            <div
+              class="clickable"
+            >
+              <div
+                class="column-name"
+              >
+                c1
+              </div>
+              <div
+                class="column-detail"
+              >
+                string (auto)
+                 
+              </div>
+            </div>
+          </div>
+          <div
+            class="rt-resizer"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="rt-tbody"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            hello
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td dimension string"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    class="-loading"
+  >
+    <div
+      class="-loading-inner"
+    >
+      Loading...
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/view-control-bar/view-control-bar.tsx b/web-console/src/views/load-data-view/schema-table/schema-table.scss
similarity index 61%
copy from web-console/src/components/view-control-bar/view-control-bar.tsx
copy to web-console/src/views/load-data-view/schema-table/schema-table.scss
index bcd3e23..d8e6b37 100644
--- a/web-console/src/components/view-control-bar/view-control-bar.tsx
+++ b/web-console/src/views/load-data-view/schema-table/schema-table.scss
@@ -16,25 +16,30 @@
  * limitations under the License.
  */
 
-import React from 'react';
+.schema-table {
+  .rt-th {
+    &.dimension {
+      background: rgba(38, 170, 201, 0.5);
 
-import './view-control-bar.scss';
+      &.long { background: rgba(19, 129, 201, 0.5); }
+      &.float { background: rgba(25, 145, 201, 0.5); }
+    }
 
-export interface ViewControlBarProps {
-  label: string;
-}
-
-export class ViewControlBar extends React.PureComponent<ViewControlBarProps, {}> {
-  constructor(props: ViewControlBarProps) {
-    super(props);
+    &.metric {
+      background: rgba(201, 191, 55, 0.5);
+    }
   }
 
-  render() {
-    const { label, children } = this.props;
+  .rt-td {
+    &.dimension {
+      background: rgba(38, 170, 201, 0.1);
+
+      &.long { background: rgba(19, 129, 201, 0.1); }
+      &.float { background: rgba(25, 145, 201, 0.1); }
+    }
 
-    return <div className="view-control-bar">
-      <div className="control-label">{label}</div>
-      {children}
-    </div>;
+    &.metric {
+      background: rgba(201, 191, 55, 0.1);
+    }
   }
 }
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/load-data-view/schema-table/schema-table.spec.tsx
similarity index 62%
copy from web-console/src/components/sql-control/sql-control.spec.tsx
copy to web-console/src/views/load-data-view/schema-table/schema-table.spec.tsx
index 1ac07be..e7c2047 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/views/load-data-view/schema-table/schema-table.spec.tsx
@@ -19,18 +19,33 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { SqlControl } from './sql-control';
+import { SchemaTable } from './schema-table';
 
-describe('sql control', () => {
+describe('schema table', () => {
   it('matches snapshot', () => {
-    const sqlControl = <SqlControl
-      initSql={'test'}
-      onRun={(query, context, wrapQuery) => {}}
-      onExplain={(sqlQuery, context) => {}}
-      queryElapsed={2}
+    const sampleData = {
+      header: ['c1'],
+      rows: [
+        {
+          raw: `{"c1":"hello"}`,
+          parsed: { c1: 'hello' }
+        }
+      ]
+    };
+
+    const schemaTable = <SchemaTable
+      sampleBundle={{
+        headerAndRows: sampleData,
+        dimensionsSpec: {},
+        metricsSpec: []
+      }}
+      columnFilter=""
+      selectedDimensionSpecIndex={-1}
+      selectedMetricSpecIndex={-1}
+      onDimensionOrMetricSelect={() => null}
     />;
 
-    const { container } = render(sqlControl);
+    const { container } = render(schemaTable);
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/views/load-data-view/schema-table/schema-table.tsx b/web-console/src/views/load-data-view/schema-table/schema-table.tsx
new file mode 100644
index 0000000..1b6f96f
--- /dev/null
+++ b/web-console/src/views/load-data-view/schema-table/schema-table.tsx
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import classNames from 'classnames';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import { TableCell } from '../../../components';
+import { caseInsensitiveContains, filterMap, sortWithPrefixSuffix } from '../../../utils';
+import {
+  DimensionSpec,
+  DimensionsSpec,
+  getDimensionSpecName,
+  getDimensionSpecType,
+  getMetricSpecName,
+  inflateDimensionSpec,
+  MetricSpec, TimestampSpec
+} from '../../../utils/ingestion-spec';
+import { HeaderAndRows, SampleEntry } from '../../../utils/sampler';
+
+import './schema-table.scss';
+
+export interface SchemaTableProps extends React.Props<any> {
+  sampleBundle: {
+    headerAndRows: HeaderAndRows;
+    dimensionsSpec: DimensionsSpec;
+    metricsSpec: MetricSpec[];
+  };
+  columnFilter: string;
+  selectedDimensionSpecIndex: number;
+  selectedMetricSpecIndex: number;
+  onDimensionOrMetricSelect: (
+    selectedDimensionSpec: DimensionSpec | null,
+    selectedDimensionSpecIndex: number,
+    selectedMetricSpec: MetricSpec | null,
+    selectedMetricSpecIndex: number
+  ) => void;
+}
+
+export class SchemaTable extends React.PureComponent<SchemaTableProps> {
+  render() {
+    const { sampleBundle, columnFilter, selectedDimensionSpecIndex, selectedMetricSpecIndex, onDimensionOrMetricSelect } = this.props;
+    const { headerAndRows, dimensionsSpec, metricsSpec } = sampleBundle;
+
+    const dimensionMetricSortedHeader = sortWithPrefixSuffix(headerAndRows.header, ['__time'], metricsSpec.map(getMetricSpecName));
+
+    return <ReactTable
+      className="schema-table -striped -highlight"
+      data={headerAndRows.rows}
+      columns={filterMap(dimensionMetricSortedHeader, (columnName, i) => {
+        if (!caseInsensitiveContains(columnName, columnFilter)) return null;
+
+        const metricSpecIndex = metricsSpec.findIndex(m => getMetricSpecName(m) === columnName);
+        const metricSpec = metricsSpec[metricSpecIndex];
+
+        if (metricSpec) {
+          const columnClassName = classNames('metric', {
+            selected: metricSpec && metricSpecIndex === selectedMetricSpecIndex
+          });
+          return {
+            Header: (
+              <div
+                className="clickable"
+                onClick={() => onDimensionOrMetricSelect(null, -1, metricSpec, metricSpecIndex)}
+              >
+                <div className="column-name">{columnName}</div>
+                <div className="column-detail">
+                  {metricSpec.type}&nbsp;
+                </div>
+              </div>
+            ),
+            headerClassName: columnClassName,
+            className: columnClassName,
+            id: String(i),
+            accessor: row => row.parsed ? row.parsed[columnName] : null,
+            Cell: row => <TableCell value={row.value}/>
+          };
+        } else {
+          const timestamp = columnName === '__time';
+          const dimensionSpecIndex = dimensionsSpec.dimensions ? dimensionsSpec.dimensions.findIndex(d => getDimensionSpecName(d) === columnName) : -1;
+          const dimensionSpec = dimensionsSpec.dimensions ? dimensionsSpec.dimensions[dimensionSpecIndex] : null;
+          const dimensionSpecType = dimensionSpec ? getDimensionSpecType(dimensionSpec) : null;
+
+          const columnClassName = classNames(timestamp ? 'timestamp' : 'dimension', dimensionSpecType || 'string', {
+            selected: dimensionSpec && dimensionSpecIndex === selectedDimensionSpecIndex
+          });
+          return {
+            Header: (
+              <div
+                className="clickable"
+                onClick={() => {
+                  if (timestamp) {
+                    onDimensionOrMetricSelect(null, -1, null, -1);
+                    return;
+                  }
+
+                  if (!dimensionSpec) return;
+                  onDimensionOrMetricSelect(inflateDimensionSpec(dimensionSpec), dimensionSpecIndex, null, -1);
+                }}
+              >
+                <div className="column-name">{columnName}</div>
+                <div className="column-detail">
+                  {timestamp ? 'long (time column)' : (dimensionSpecType || 'string (auto)')}&nbsp;
+                </div>
+              </div>
+            ),
+            headerClassName: columnClassName,
+            className: columnClassName,
+            id: String(i),
+            accessor: (row: SampleEntry) => row.parsed ? row.parsed[columnName] : null,
+            Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
+          };
+        }
+      })}
+      defaultPageSize={50}
+      showPagination={false}
+      sortable={false}
+    />;
+  }
+}
diff --git a/web-console/src/views/load-data-view/transform-table/__snapshots__/transform-table.spec.tsx.snap b/web-console/src/views/load-data-view/transform-table/__snapshots__/transform-table.spec.tsx.snap
new file mode 100644
index 0000000..2febec3
--- /dev/null
+++ b/web-console/src/views/load-data-view/transform-table/__snapshots__/transform-table.spec.tsx.snap
@@ -0,0 +1,1014 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`transform table matches snapshot 1`] = `
+<div
+  class="ReactTable transform-table -striped -highlight"
+>
+  <div
+    class="rt-table"
+    role="grid"
+  >
+    <div
+      class="rt-thead -header"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr"
+        role="row"
+      >
+        <div
+          class="rt-th rt-resizable-header"
+          role="columnheader"
+          style="flex: 100 0 auto; width: 100px;"
+          tabindex="-1"
+        >
+          <div
+            class="rt-resizable-header-content"
+          >
+            <div
+              class="clickable"
+            >
+              <div
+                class="column-name"
+              >
+                c1
+              </div>
+              <div
+                class="column-detail"
+              >
+                
+                 
+              </div>
+            </div>
+          </div>
+          <div
+            class="rt-resizer"
+          />
+        </div>
+      </div>
+    </div>
+    <div
+      class="rt-tbody"
+      style="min-width: 100px;"
+    >
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            hello
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -odd"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+      <div
+        class="rt-tr-group"
+        role="rowgroup"
+      >
+        <div
+          class="rt-tr -padRow -even"
+          role="row"
+        >
+          <div
+            class="rt-td"
+            role="gridcell"
+            style="flex: 100 0 auto; width: 100px;"
+          >
+            <span>
+               
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div
+    class="-loading"
+  >
+    <div
+      class="-loading-inner"
+    >
+      Loading...
+    </div>
+  </div>
+</div>
+`;
diff --git a/web-console/src/components/menu-checkbox/menu-checkbox.tsx b/web-console/src/views/load-data-view/transform-table/transform-table.scss
similarity index 73%
copy from web-console/src/components/menu-checkbox/menu-checkbox.tsx
copy to web-console/src/views/load-data-view/transform-table/transform-table.scss
index 659a78c..0b85f72 100644
--- a/web-console/src/components/menu-checkbox/menu-checkbox.tsx
+++ b/web-console/src/views/load-data-view/transform-table/transform-table.scss
@@ -16,16 +16,16 @@
  * limitations under the License.
  */
 
-import { Checkbox, ICheckboxProps } from '@blueprintjs/core';
-import React from 'react';
-
-import './menu-checkbox.scss';
-
-export class MenuCheckbox extends React.PureComponent<ICheckboxProps, {}> {
+.transform-table {
+  .rt-th {
+    &.transformed {
+      background: rgba(201, 128, 22, 0.2);
+    }
+  }
 
-  render() {
-    return <li className="menu-checkbox">
-      <Checkbox {...this.props}/>
-    </li>;
+  .rt-td {
+    &.transformed {
+      background: rgba(201, 128, 22, 0.05);
+    }
   }
 }
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/load-data-view/transform-table/transform-table.spec.tsx
similarity index 65%
copy from web-console/src/components/sql-control/sql-control.spec.tsx
copy to web-console/src/views/load-data-view/transform-table/transform-table.spec.tsx
index 1ac07be..b750f20 100644
--- a/web-console/src/components/sql-control/sql-control.spec.tsx
+++ b/web-console/src/views/load-data-view/transform-table/transform-table.spec.tsx
@@ -19,18 +19,30 @@
 import React from 'react';
 import { render } from 'react-testing-library';
 
-import { SqlControl } from './sql-control';
+import { TransformTable } from './transform-table';
 
-describe('sql control', () => {
+describe('transform table', () => {
   it('matches snapshot', () => {
-    const sqlControl = <SqlControl
-      initSql={'test'}
-      onRun={(query, context, wrapQuery) => {}}
-      onExplain={(sqlQuery, context) => {}}
-      queryElapsed={2}
+    const sampleData = {
+      header: ['c1'],
+      rows: [
+        {
+          raw: `{"c1":"hello"}`,
+          parsed: { c1: 'hello' }
+        }
+      ]
+    };
+
+    const transformTable = <TransformTable
+      sampleData={sampleData}
+      columnFilter=""
+      transformedColumnsOnly={false}
+      transforms={[]}
+      selectedTransformIndex={-1}
+      onTransformSelect={() => null}
     />;
 
-    const { container } = render(sqlControl);
+    const { container } = render(transformTable);
     expect(container.firstChild).toMatchSnapshot();
   });
 });
diff --git a/web-console/src/views/load-data-view/transform-table/transform-table.tsx b/web-console/src/views/load-data-view/transform-table/transform-table.tsx
new file mode 100644
index 0000000..5a38923
--- /dev/null
+++ b/web-console/src/views/load-data-view/transform-table/transform-table.tsx
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import classNames from 'classnames';
+import React from 'react';
+import ReactTable from 'react-table';
+
+import { TableCell } from '../../../components';
+import { caseInsensitiveContains, filterMap } from '../../../utils';
+import { escapeColumnName } from '../../../utils/druid-expression';
+import { Transform } from '../../../utils/ingestion-spec';
+import { HeaderAndRows } from '../../../utils/sampler';
+
+import './transform-table.scss';
+
+export interface TransformTableProps extends React.Props<any> {
+  sampleData: HeaderAndRows;
+  columnFilter: string;
+  transformedColumnsOnly: boolean;
+  transforms: Transform[];
+  selectedTransformIndex: number;
+  onTransformSelect: (transform: Transform, index: number) => void;
+}
+
+export class TransformTable extends React.PureComponent<TransformTableProps> {
+  render() {
+    const { sampleData, columnFilter, transformedColumnsOnly, transforms, selectedTransformIndex, onTransformSelect } = this.props;
+
+    return <ReactTable
+      className="transform-table -striped -highlight"
+      data={sampleData.rows}
+      columns={filterMap(sampleData.header, (columnName, i) => {
+        if (!caseInsensitiveContains(columnName, columnFilter)) return null;
+        const timestamp = columnName === '__time';
+        const transformIndex = transforms.findIndex(f => f.name === columnName);
+        if (transformIndex === -1 && transformedColumnsOnly) return null;
+        const transform = transforms[transformIndex];
+
+        const columnClassName = classNames({
+          transformed: transform,
+          selected: transform && transformIndex === selectedTransformIndex
+        });
+        return {
+          Header: (
+            <div
+              className={classNames('clickable')}
+              onClick={() => {
+                if (transform) {
+                  onTransformSelect(transform, transformIndex);
+                } else {
+                  onTransformSelect({
+                    type: 'expression',
+                    name: columnName,
+                    expression: escapeColumnName(columnName)
+                  }, transformIndex);
+                }
+              }}
+            >
+              <div className="column-name">{columnName}</div>
+              <div className="column-detail">
+                {transform ? `= ${transform.expression}` : ''}&nbsp;
+              </div>
+            </div>
+          ),
+          headerClassName: columnClassName,
+          className: columnClassName,
+          id: String(i),
+          accessor: row => row.parsed ? row.parsed[columnName] : null,
+          Cell: row => <TableCell value={row.value} timestamp={timestamp}/>
+        };
+      })}
+      defaultPageSize={50}
+      showPagination={false}
+      sortable={false}
+    />;
+  }
+}
diff --git a/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap b/web-console/src/views/sql-view/sql-control/__snapshots__/sql-control.spec.tsx.snap
similarity index 98%
rename from web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
rename to web-console/src/views/sql-view/sql-control/__snapshots__/sql-control.spec.tsx.snap
index fcb5b8f..80ab5c4 100644
--- a/web-console/src/components/sql-control/__snapshots__/sql-control.spec.tsx.snap
+++ b/web-console/src/views/sql-view/sql-control/__snapshots__/sql-control.spec.tsx.snap
@@ -8,7 +8,7 @@ exports[`sql control matches snapshot 1`] = `
     class="ace-container"
   >
     <div
-      class=" ace_editor ace-solarized-dark ace_dark ace_focus"
+      class=" ace_editor ace-tm ace_focus"
       id="ace-editor"
       style="width: 100%; height: 200px; font-size: 14px;"
     >
diff --git a/web-console/src/components/sql-control/sql-control.scss b/web-console/src/views/sql-view/sql-control/sql-control.scss
similarity index 98%
rename from web-console/src/components/sql-control/sql-control.scss
rename to web-console/src/views/sql-view/sql-control/sql-control.scss
index 694de36..95c798b 100644
--- a/web-console/src/components/sql-control/sql-control.scss
+++ b/web-console/src/views/sql-view/sql-control/sql-control.scss
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-@import "../../variables";
+@import "../../../variables";
 
 .sql-control {
   .ace-container {
diff --git a/web-console/src/components/sql-control/sql-control.spec.tsx b/web-console/src/views/sql-view/sql-control/sql-control.spec.tsx
similarity index 100%
rename from web-console/src/components/sql-control/sql-control.spec.tsx
rename to web-console/src/views/sql-view/sql-control/sql-control.spec.tsx
diff --git a/web-console/src/components/sql-control/sql-control.tsx b/web-console/src/views/sql-view/sql-control/sql-control.tsx
similarity index 96%
rename from web-console/src/components/sql-control/sql-control.tsx
rename to web-console/src/views/sql-view/sql-control/sql-control.tsx
index 4006105..44730b9 100644
--- a/web-console/src/components/sql-control/sql-control.tsx
+++ b/web-console/src/views/sql-view/sql-control/sql-control.tsx
@@ -29,20 +29,15 @@ import { Hotkey, Hotkeys, HotkeysTarget } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
 import ace from 'brace';
-import 'brace/ext/language_tools';
-import 'brace/mode/hjson';
-import 'brace/mode/sql';
-import 'brace/theme/solarized_dark';
 import Hjson from 'hjson';
 import React from 'react';
 import AceEditor from 'react-ace';
 import ReactDOMServer from 'react-dom/server';
 
-import { SQLFunctionDoc } from '../../../lib/sql-function-doc';
-import { AppToaster } from '../../singletons/toaster';
-import { DRUID_DOCS_RUNE, DRUID_DOCS_SQL } from '../../variables';
-
-import { MenuCheckbox } from './../menu-checkbox/menu-checkbox';
+import { SQLFunctionDoc } from '../../../../lib/sql-function-doc';
+import { MenuCheckbox } from '../../../components';
+import { AppToaster } from '../../../singletons/toaster';
+import { DRUID_DOCS_RUNE, DRUID_DOCS_SQL } from '../../../variables';
 
 import './sql-control.scss';
 
diff --git a/web-console/src/views/sql-view/sql-view.tsx b/web-console/src/views/sql-view/sql-view.tsx
index 178b980..fedd243 100644
--- a/web-console/src/views/sql-view/sql-view.tsx
+++ b/web-console/src/views/sql-view/sql-view.tsx
@@ -21,7 +21,7 @@ import React from 'react';
 import SplitterLayout from 'react-splitter-layout';
 import ReactTable from 'react-table';
 
-import { SqlControl, TableCell } from '../../components';
+import { TableCell } from '../../components';
 import { QueryPlanDialog } from '../../dialogs';
 import {
   BasicQueryExplanation,
@@ -34,6 +34,8 @@ import {
   SemiJoinQueryExplanation
 } from '../../utils';
 
+import { SqlControl } from './sql-control/sql-control';
+
 import './sql-view.scss';
 
 interface QueryWithContext {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org