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

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


The following commit(s) were added to refs/heads/master by this push:
     new be936c2  style: listviews closer to SIP-34 (#10094)
be936c2 is described below

commit be936c2eb89fa09ed6147fb9f2dc4c63ed1390bd
Author: ʈᵃᵢ <tdupree...@gmail.com>
AuthorDate: Tue Jun 23 14:17:28 2020 -0700

    style: listviews closer to SIP-34 (#10094)
---
 .../components/ListView/ListView_spec.jsx          |   3 +-
 .../javascripts/views/chartList/ChartList_spec.jsx |   4 +
 .../views/dashboardList/DashboardList_spec.jsx     |   4 +
 .../javascripts/welcome/DashboardTable_spec.jsx    |   8 +-
 superset-frontend/src/components/AvatarIcon.tsx    |  29 ++-
 .../src/components/ListView/ListView.tsx           | 211 ++++++++++-----------
 .../src/components/ListView/ListViewStyles.less    | 169 ++++++++++-------
 .../src/components/ListView/Pagination.tsx         |  11 +-
 .../src/components/ListView/TableCollection.tsx    |  82 ++++++--
 superset-frontend/src/components/Menu/SubMenu.tsx  |  16 +-
 superset-frontend/src/components/Pagination.tsx    | 132 +++++++++++++
 .../src/types/react-table-config.d.ts              |  10 +-
 superset-frontend/src/utils/common.js              |   4 +
 .../src/views/chartList/ChartList.tsx              | 103 +++++-----
 .../src/views/dashboardList/DashboardList.tsx      | 125 ++++++------
 .../src/views/datasetList/DatasetList.tsx          | 179 +++++++++--------
 superset-frontend/stylesheets/less/variables.less  |   4 -
 17 files changed, 682 insertions(+), 412 deletions(-)

diff --git 
a/superset-frontend/spec/javascripts/components/ListView/ListView_spec.jsx 
b/superset-frontend/spec/javascripts/components/ListView/ListView_spec.jsx
index e5e04d5..52e15ff 100644
--- a/superset-frontend/spec/javascripts/components/ListView/ListView_spec.jsx
+++ b/superset-frontend/spec/javascripts/components/ListView/ListView_spec.jsx
@@ -19,13 +19,14 @@
 import React from 'react';
 import { mount, shallow } from 'enzyme';
 import { act } from 'react-dom/test-utils';
-import { MenuItem, Pagination } from 'react-bootstrap';
+import { MenuItem } from 'react-bootstrap';
 import Select from 'src/components/Select';
 import { QueryParamProvider } from 'use-query-params';
 
 import ListView from 'src/components/ListView/ListView';
 import ListViewFilters from 'src/components/ListView/Filters';
 import ListViewPagination from 'src/components/ListView/Pagination';
+import Pagination from 'src/components/Pagination';
 import { areArraysShallowEqual } from 'src/reduxUtils';
 import { ThemeProvider } from 'emotion-theming';
 import { supersetTheme } from '@superset-ui/style';
diff --git 
a/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx 
b/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx
index d5785bf..1ec7275 100644
--- a/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx
+++ b/superset-frontend/spec/javascripts/views/chartList/ChartList_spec.jsx
@@ -21,6 +21,8 @@ import { mount } from 'enzyme';
 import thunk from 'redux-thunk';
 import configureStore from 'redux-mock-store';
 import fetchMock from 'fetch-mock';
+import { ThemeProvider } from 'emotion-theming';
+import { supersetTheme } from '@superset-ui/style';
 
 import ChartList from 'src/views/chartList/ChartList';
 import ListView from 'src/components/ListView/ListView';
@@ -77,6 +79,8 @@ describe('ChartList', () => {
   const mockedProps = {};
   const wrapper = mount(<ChartList {...mockedProps} />, {
     context: { store },
+    wrappingComponent: ThemeProvider,
+    wrappingComponentProps: { theme: supersetTheme },
   });
 
   it('renders', () => {
diff --git 
a/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx 
b/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx
index 086d9d1..456035e 100644
--- 
a/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx
+++ 
b/superset-frontend/spec/javascripts/views/dashboardList/DashboardList_spec.jsx
@@ -21,6 +21,8 @@ import { mount } from 'enzyme';
 import thunk from 'redux-thunk';
 import configureStore from 'redux-mock-store';
 import fetchMock from 'fetch-mock';
+import { ThemeProvider } from 'emotion-theming';
+import { supersetTheme } from '@superset-ui/style';
 
 import DashboardList from 'src/views/dashboardList/DashboardList';
 import ListView from 'src/components/ListView/ListView';
@@ -67,6 +69,8 @@ describe('DashboardList', () => {
   const mockedProps = {};
   const wrapper = mount(<DashboardList {...mockedProps} />, {
     context: { store },
+    wrappingComponent: ThemeProvider,
+    wrappingComponentProps: { theme: supersetTheme },
   });
 
   it('renders', () => {
diff --git a/superset-frontend/spec/javascripts/welcome/DashboardTable_spec.jsx 
b/superset-frontend/spec/javascripts/welcome/DashboardTable_spec.jsx
index a31761a..2fe659b 100644
--- a/superset-frontend/spec/javascripts/welcome/DashboardTable_spec.jsx
+++ b/superset-frontend/spec/javascripts/welcome/DashboardTable_spec.jsx
@@ -21,6 +21,8 @@ import { mount } from 'enzyme';
 import thunk from 'redux-thunk';
 import configureStore from 'redux-mock-store';
 import fetchMock from 'fetch-mock';
+import { ThemeProvider } from 'emotion-theming';
+import { supersetTheme } from '@superset-ui/style';
 
 import ListView from 'src/components/ListView/ListView';
 import DashboardTable from 'src/welcome/DashboardTable';
@@ -36,7 +38,11 @@ fetchMock.get(dashboardsEndpoint, { result: mockDashboards 
});
 
 function setup() {
   // use mount because data fetching is triggered on mount
-  return mount(<DashboardTable />, { context: { store } });
+  return mount(<DashboardTable />, {
+    context: { store },
+    wrappingComponent: ThemeProvider,
+    wrappingComponentProps: { theme: supersetTheme },
+  });
 }
 
 describe('DashboardTable', () => {
diff --git a/superset-frontend/src/components/AvatarIcon.tsx 
b/superset-frontend/src/components/AvatarIcon.tsx
index 4d86983..7dcf8f7 100644
--- a/superset-frontend/src/components/AvatarIcon.tsx
+++ b/superset-frontend/src/components/AvatarIcon.tsx
@@ -19,15 +19,16 @@
 import React from 'react';
 import styled from '@superset-ui/style';
 import { getCategoricalSchemeRegistry } from '@superset-ui/color';
-import { Tooltip, OverlayTrigger } from 'react-bootstrap';
 import Avatar, { ConfigProvider } from 'react-avatar';
+import TooltipWrapper from 'src/components/TooltipWrapper';
 
 interface Props {
   firstName: string;
-  iconSize: string;
   lastName: string;
   tableName: string;
   userName: string;
+  iconSize: number;
+  textSize: number;
 }
 
 const colorList = getCategoricalSchemeRegistry().get();
@@ -42,18 +43,26 @@ export default function AvatarIcon({
   lastName,
   userName,
   iconSize,
+  textSize,
 }: Props) {
   const uniqueKey = `${tableName}-${userName}`;
   const fullName = `${firstName} ${lastName}`;
 
   return (
-    <ConfigProvider colors={colorList && colorList.colors}>
-      <OverlayTrigger
-        placement="right"
-        overlay={<Tooltip id={`${uniqueKey}-tooltip`}>{fullName}</Tooltip>}
-      >
-        <StyledAvatar key={uniqueKey} name={fullName} size={iconSize} round />
-      </OverlayTrigger>
-    </ConfigProvider>
+    <TooltipWrapper
+      placement="bottom"
+      label={`${uniqueKey}-tooltip`}
+      tooltip={fullName}
+    >
+      <ConfigProvider colors={colorList && colorList.colors}>
+        <StyledAvatar
+          key={uniqueKey}
+          name={fullName}
+          size={String(iconSize)}
+          textSizeRatio={iconSize / textSize}
+          round
+        />
+      </ConfigProvider>
+    </TooltipWrapper>
   );
 }
diff --git a/superset-frontend/src/components/ListView/ListView.tsx 
b/superset-frontend/src/components/ListView/ListView.tsx
index 27f68cd..1017fbe 100644
--- a/superset-frontend/src/components/ListView/ListView.tsx
+++ b/superset-frontend/src/components/ListView/ListView.tsx
@@ -19,7 +19,8 @@
 import { t } from '@superset-ui/translation';
 import React, { FunctionComponent } from 'react';
 import { Col, DropdownButton, MenuItem, Row } from 'react-bootstrap';
-import IndeterminateCheckbox from '../IndeterminateCheckbox';
+import Loading from 'src/components/Loading';
+import IndeterminateCheckbox from 'src/components/IndeterminateCheckbox';
 import TableCollection from './TableCollection';
 import Pagination from './Pagination';
 import { FilterMenu, FilterInputs } from './LegacyFilters';
@@ -37,7 +38,6 @@ interface Props {
   fetchData: (conf: FetchDataConfig) => any;
   loading: boolean;
   className?: string;
-  title?: string;
   initialSort?: SortColumn[];
   filters?: Filters;
   bulkActions?: Array<{
@@ -59,6 +59,7 @@ const bulkSelectColumnConfig = {
     />
   ),
   id: 'selection',
+  size: 'sm',
 };
 
 const ListView: FunctionComponent<Props> = ({
@@ -70,7 +71,6 @@ const ListView: FunctionComponent<Props> = ({
   loading,
   initialSort = [],
   className = '',
-  title = '',
   filters = [],
   bulkActions = [],
   useNewUIFilters = false,
@@ -116,124 +116,111 @@ const ListView: FunctionComponent<Props> = ({
       }
     });
   }
-
+  if (loading && !data.length) {
+    return <Loading />;
+  }
   return (
-    <div className={`superset-list-view ${className}`}>
-      <div className="header">
-        {!useNewUIFilters && (
-          <>
-            {title && filterable && (
-              <>
-                <Row>
-                  <Col md={11}>
-                    <h2>{t(title)}</h2>
-                  </Col>
-                  {filterable && (
-                    <Col md={1}>
-                      <FilterMenu
-                        filters={filters}
-                        internalFilters={internalFilters}
-                        setInternalFilters={setInternalFilters}
-                      />
-                    </Col>
-                  )}
-                </Row>
-                <hr />
-                <FilterInputs
-                  internalFilters={internalFilters}
-                  filters={filters}
-                  updateInternalFilter={updateInternalFilter}
-                  removeFilterAndApply={removeFilterAndApply}
-                  filtersApplied={filtersApplied}
-                  applyFilters={applyFilters}
-                />
-              </>
-            )}
-          </>
-        )}
-        {useNewUIFilters && (
-          <>
-            <Row>
-              <Col md={10}>
-                <h2>{t(title)}</h2>
-              </Col>
-            </Row>
-            <hr />
+    <div className="superset-list-view-container">
+      <div className={`superset-list-view ${className}`}>
+        <div className="header">
+          {!useNewUIFilters && filterable && (
+            <>
+              <Row>
+                <Col md={10} />
+                <Col md={2}>
+                  <FilterMenu
+                    filters={filters}
+                    internalFilters={internalFilters}
+                    setInternalFilters={setInternalFilters}
+                  />
+                </Col>
+              </Row>
+              <hr />
+              <FilterInputs
+                internalFilters={internalFilters}
+                filters={filters}
+                updateInternalFilter={updateInternalFilter}
+                removeFilterAndApply={removeFilterAndApply}
+                filtersApplied={filtersApplied}
+                applyFilters={applyFilters}
+              />
+            </>
+          )}
+          {useNewUIFilters && filterable && (
             <FilterControls
               filters={filters}
               internalFilters={internalFilters}
               updateFilterValue={applyFilterValue}
             />
-          </>
-        )}
-      </div>
-      <div className="body">
-        <TableCollection
-          getTableProps={getTableProps}
-          getTableBodyProps={getTableBodyProps}
-          prepareRow={prepareRow}
-          headerGroups={headerGroups}
-          rows={rows}
-          loading={loading}
-        />
-      </div>
-      <div className="footer">
-        <Row>
-          <Col md={2}>
-            <div className="form-actions-container">
-              <div className="btn-group">
-                {bulkActions.length > 0 && (
-                  <DropdownButton
-                    id="bulk-actions"
-                    bsSize="small"
-                    bsStyle="default"
-                    noCaret
-                    title={
-                      <>
-                        {t('Actions')} <span className="caret" />
-                      </>
-                    }
-                  >
-                    {bulkActions.map(action => (
-                      // @ts-ignore
-                      <MenuItem
-                        key={action.key}
-                        eventKey={selectedFlatRows}
+          )}
+        </div>
+        <div className="body">
+          <TableCollection
+            getTableProps={getTableProps}
+            getTableBodyProps={getTableBodyProps}
+            prepareRow={prepareRow}
+            headerGroups={headerGroups}
+            rows={rows}
+            loading={loading}
+          />
+        </div>
+        <div className="footer">
+          <Row>
+            <Col>
+              <div className="form-actions-container">
+                <div className="btn-group">
+                  {bulkActions.length > 0 && (
+                    <DropdownButton
+                      id="bulk-actions"
+                      bsSize="small"
+                      bsStyle="default"
+                      noCaret
+                      title={
+                        <>
+                          {t('Actions')} <span className="caret" />
+                        </>
+                      }
+                    >
+                      {bulkActions.map(action => (
                         // @ts-ignore
-                        onSelect={(selectedRows: typeof selectedFlatRows) => {
-                          action.onSelect(
-                            selectedRows.map((r: any) => r.original),
-                          );
-                        }}
-                      >
-                        {action.name}
-                      </MenuItem>
-                    ))}
-                  </DropdownButton>
-                )}
+                        <MenuItem
+                          key={action.key}
+                          eventKey={selectedFlatRows}
+                          // @ts-ignore
+                          onSelect={(selectedRows: typeof selectedFlatRows) => 
{
+                            action.onSelect(
+                              selectedRows.map((r: any) => r.original),
+                            );
+                          }}
+                        >
+                          {action.name}
+                        </MenuItem>
+                      ))}
+                    </DropdownButton>
+                  )}
+                </div>
               </div>
-            </div>
-          </Col>
-          <Col md={8} className="text-center">
-            <Pagination
-              totalPages={pageCount || 0}
-              currentPage={pageCount ? pageIndex + 1 : 0}
-              onChange={(p: number) => gotoPage(p - 1)}
-              hideFirstAndLastPageLinks
-            />
-          </Col>
-          <Col md={2}>
-            <span className="pull-right">
-              {t('showing')}{' '}
-              <strong>
-                {pageSize * pageIndex + (rows.length && 1)}-
-                {pageSize * pageIndex + rows.length}
-              </strong>{' '}
-              {t('of')} <strong>{count}</strong>
-            </span>
-          </Col>
-        </Row>
+            </Col>
+
+            <Col>
+              <span className="row-count-container">
+                showing{' '}
+                <strong>
+                  {pageSize * pageIndex + (rows.length && 1)}-
+                  {pageSize * pageIndex + rows.length}
+                </strong>{' '}
+                of <strong>{count}</strong>
+              </span>
+            </Col>
+          </Row>
+        </div>
       </div>
+      <Pagination
+        totalPages={pageCount || 0}
+        currentPage={pageCount ? pageIndex + 1 : 0}
+        onChange={(p: number) => gotoPage(p - 1)}
+        hideFirstAndLastPageLinks
+      />
     </div>
   );
 };
diff --git a/superset-frontend/src/components/ListView/ListViewStyles.less 
b/superset-frontend/src/components/ListView/ListViewStyles.less
index a5f3d87..f922f1b 100644
--- a/superset-frontend/src/components/ListView/ListViewStyles.less
+++ b/superset-frontend/src/components/ListView/ListViewStyles.less
@@ -19,92 +19,133 @@
 
 @import '~stylesheets/less/variables.less';
 
-.superset-list-view {
-  .filter-dropdown {
-    margin-top: 20px;
-  }
+.superset-list-view-container {
+  text-align: center;
+
+  .superset-list-view {
+    text-align: left;
+    background-color: white;
+    border-radius: 4px 0;
+    margin: 0 16px;
+    padding-bottom: 48px;
+
+    .body {
+      overflow: scroll;
+    }
 
-  .filter-column {
-    height: 30px;
-    padding: 5px;
-    font-size: 16px;
-  }
+    .filter-dropdown {
+      margin-top: 20px;
+    }
 
-  .filter-close {
-    height: 30px;
-    padding: 5px;
+    .filter-column {
+      height: 30px;
+      padding: 5px;
+      font-size: 16px;
+    }
 
-    i {
-      font-size: 20px;
+    .filter-close {
+      height: 30px;
+      padding: 5px;
+
+      i {
+        font-size: 20px;
+      }
     }
-  }
 
-  .table-row-loader {
-    animation: shimmer 2s infinite;
-    background: linear-gradient(
-      to right,
-      #f6f7f8 0%,
-      #edeef1 20%,
-      #f6f7f8 40%,
-      #f6f7f8 100%
-    );
-    background-size: 1000px 100%;
-
-    span {
-      visibility: hidden;
+    .table-cell-loader {
+      position: relative;
+
+      .loading-bar {
+        background-color: @brand-secondary-light4;
+        border-radius: 7px;
+
+        span {
+          visibility: hidden;
+        }
+      }
+
+      &:after {
+        position: absolute;
+        transform: translateY(-50%);
+        top: 50%;
+        left: 0;
+        content: '';
+        display: block;
+        width: 100%;
+        height: 48px;
+        background-image: linear-gradient(
+          100deg,
+          rgba(255, 255, 255, 0),
+          rgba(255, 255, 255, 0.5) 60%,
+          rgba(255, 255, 255, 0) 80%
+        );
+        background-size: 200px 48px;
+        background-position: -100px 0;
+        background-repeat: no-repeat;
+        animation: loading-shimmer 1s infinite;
+      }
     }
-  }
 
-  .actions {
-    font-size: 20px;
-    white-space: nowrap;
+    .actions {
+      white-space: nowrap;
+      font-size: 24px;
+      min-width: 100px;
 
-    width: 100px;
+      svg,
+      i {
+        margin-right: 8px;
 
-    svg {
-      &:hover {
-        path {
-          fill: @primary-color;
+        &:hover {
+          path {
+            fill: @primary-color;
+          }
         }
       }
     }
-  }
 
-  .action-button {
-    margin: 0 8px;
-  }
+    .table-row {
+      &:hover {
+        background-color: @brand-secondary-light5;
+      }
+    }
+
+    .table-row-selected {
+      background-color: @brand-secondary-light4;
 
-  .table-row {
-    &:hover {
-      background-color: @table-hover;
+      &:hover {
+        background-color: @brand-secondary-light4;
+      }
     }
-  }
 
-  .table-row-selected {
-    background-color: @table-selected;
+    .table-cell {
+      text-overflow: ellipsis;
+      overflow: hidden;
+      white-space: nowrap;
+      max-width: 300px;
+    }
 
-    &:hover {
-      background-color: @table-selected;
+    .sort-icon {
+      position: absolute;
     }
-  }
 
-  .table-cell {
-    max-width: 200px;
-    text-overflow: ellipsis;
-    overflow: hidden;
-  }
+    .form-actions-container {
+      position: absolute;
+      left: 28px;
+    }
 
-  .sort-icon {
-    position: absolute;
+    .row-count-container {
+      position: absolute;
+      right: 28px;
+    }
   }
-}
 
-@keyframes shimmer {
-  0% {
-    background-position: -1000px 0;
-  }
+  @keyframes loading-shimmer {
+    40% {
+      background-position: 100% 0;
+    }
 
-  100% {
-    background-position: 1000px 0;
+    100% {
+      background-position: 100% 0;
+    }
   }
 }
diff --git a/superset-frontend/src/components/ListView/Pagination.tsx 
b/superset-frontend/src/components/ListView/Pagination.tsx
index 03b8663..6d1d272 100644
--- a/superset-frontend/src/components/ListView/Pagination.tsx
+++ b/superset-frontend/src/components/ListView/Pagination.tsx
@@ -17,8 +17,7 @@
  * under the License.
  */
 import React from 'react';
-// @ts-ignore
-import { Pagination } from 'react-bootstrap';
+import Pagination from 'src/components/Pagination';
 import {
   createUltimatePagination,
   ITEM_TYPES,
@@ -35,18 +34,14 @@ const ListViewPagination = createUltimatePagination({
     [ITEM_TYPES.ELLIPSIS]: ({ isActive, onClick }) => (
       <Pagination.Ellipsis disabled={isActive} onClick={onClick} />
     ),
-    [ITEM_TYPES.FIRST_PAGE_LINK]: ({ isActive, onClick }) => (
-      <Pagination.First disabled={isActive} onClick={onClick} />
-    ),
     [ITEM_TYPES.PREVIOUS_PAGE_LINK]: ({ isActive, onClick }) => (
       <Pagination.Prev disabled={isActive} onClick={onClick} />
     ),
     [ITEM_TYPES.NEXT_PAGE_LINK]: ({ isActive, onClick }) => (
       <Pagination.Next disabled={isActive} onClick={onClick} />
     ),
-    [ITEM_TYPES.LAST_PAGE_LINK]: ({ isActive, onClick }) => (
-      <Pagination.Last disabled={isActive} onClick={onClick} />
-    ),
+    [ITEM_TYPES.FIRST_PAGE_LINK]: () => null,
+    [ITEM_TYPES.LAST_PAGE_LINK]: () => null,
   },
 });
 
diff --git a/superset-frontend/src/components/ListView/TableCollection.tsx 
b/superset-frontend/src/components/ListView/TableCollection.tsx
index cc8b8bc..b08114b 100644
--- a/superset-frontend/src/components/ListView/TableCollection.tsx
+++ b/superset-frontend/src/components/ListView/TableCollection.tsx
@@ -19,6 +19,7 @@
 import React from 'react';
 import cx from 'classnames';
 import { TableInstance } from 'react-table';
+import styled from '@superset-ui/style';
 import Icon from 'src/components/Icon';
 
 interface Props {
@@ -29,6 +30,56 @@ interface Props {
   rows: TableInstance['rows'];
   loading: boolean;
 }
+
+const Table = styled.table`
+  th {
+    &.xs {
+      min-width: 25px;
+    }
+    &.sm {
+      min-width: 50px;
+    }
+    &.md {
+      min-width: 75px;
+    }
+    &.lg {
+      min-width: 100px;
+    }
+    &.xl {
+      min-width: 150px;
+    }
+    &.xxl {
+      min-width: 200px;
+    }
+
+    svg {
+      display: inline-block;
+      top: 6px;
+      position: relative;
+    }
+  }
+  td {
+    &.xs {
+      width: 25px;
+    }
+    &.sm {
+      width: 50px;
+    }
+    &.md {
+      width: 75px;
+    }
+    &.lg {
+      width: 100px;
+    }
+    &.xl {
+      width: 150px;
+    }
+    &.xxl {
+      width: 200px;
+    }
+  }
+`;
+
 export default function TableCollection({
   getTableProps,
   getTableBodyProps,
@@ -38,29 +89,31 @@ export default function TableCollection({
   loading,
 }: Props) {
   return (
-    <table {...getTableProps()} className="table table-hover">
+    <Table {...getTableProps()} className="table table-hover">
       <thead>
         {headerGroups.map(headerGroup => (
           <tr {...headerGroup.getHeaderGroupProps()}>
             {headerGroup.headers.map(column => {
               let sortIcon = <Icon name="sort" />;
-              if (column.isSortedDesc) {
+              if (column.isSorted && column.isSortedDesc) {
                 sortIcon = <Icon name="sort-desc" />;
-              } else if (!column.isSortedDesc) {
+              } else if (column.isSorted && !column.isSortedDesc) {
                 sortIcon = <Icon name="sort-asc" />;
               }
-
               return column.hidden ? null : (
                 <th
                   {...column.getHeaderProps(
                     column.sortable ? column.getSortByToggleProps() : {},
                   )}
                   data-test="sort-header"
+                  className={cx({
+                    [column.size || '']: column.size,
+                  })}
                 >
-                  <span>{column.render('Header')}</span>
-                  {column.sortable && (
-                    <span className="sort-icon">{sortIcon}</span>
-                  )}
+                  <span>
+                    {column.render('Header')}
+                    {column.sortable && sortIcon}
+                  </span>
                 </th>
               );
             })}
@@ -74,7 +127,6 @@ export default function TableCollection({
             <tr
               {...row.getRowProps()}
               className={cx({
-                'table-row-loader': loading,
                 'table-row-selected': row.isSelected,
               })}
               onMouseEnter={() => row.setState && row.setState({ hover: true 
})}
@@ -86,14 +138,18 @@ export default function TableCollection({
                 if (cell.column.hidden) return null;
 
                 const columnCellProps = cell.column.cellProps || {};
-
                 return (
                   <td
-                    className="table-cell"
+                    className={cx('table-cell', {
+                      'table-cell-loader': loading,
+                      [cell.column.size || '']: cell.column.size,
+                    })}
                     {...cell.getCellProps()}
                     {...columnCellProps}
                   >
-                    <span>{cell.render('Cell')}</span>
+                    <span className={cx({ 'loading-bar': loading })}>
+                      <span>{cell.render('Cell')}</span>
+                    </span>
                   </td>
                 );
               })}
@@ -101,6 +157,6 @@ export default function TableCollection({
           );
         })}
       </tbody>
-    </table>
+    </Table>
   );
 }
diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx 
b/superset-frontend/src/components/Menu/SubMenu.tsx
index f0fa2c1..f565af0 100644
--- a/superset-frontend/src/components/Menu/SubMenu.tsx
+++ b/superset-frontend/src/components/Menu/SubMenu.tsx
@@ -64,11 +64,10 @@ const StyledHeader = styled.header`
 `;
 
 interface SubMenuProps {
-  createButton: { name: string; url: string | null };
-  canCreate: boolean;
-  label: string;
+  createButton?: { name: string; url: string | null };
+  canCreate?: boolean;
   name: string;
-  childs: Array<{ label: string; name: string; url: string }>;
+  childs?: Array<{ label: string; name: string; url: string }>;
 }
 
 interface SubMenuState {
@@ -78,7 +77,10 @@ interface SubMenuState {
 
 class SubMenu extends React.PureComponent<SubMenuProps, SubMenuState> {
   state: SubMenuState = {
-    selectedMenu: this.props.childs[0] && this.props.childs[0].label,
+    selectedMenu:
+      this.props.childs && this.props.childs[0]
+        ? this.props.childs[0].label
+        : '',
     isModalOpen: false,
   };
 
@@ -99,7 +101,7 @@ class SubMenu extends React.PureComponent<SubMenuProps, 
SubMenuState> {
       <StyledHeader>
         <Navbar inverse fluid role="navigation">
           <Navbar.Header>
-            <Navbar.Brand>{this.props.label}</Navbar.Brand>
+            <Navbar.Brand>{this.props.name}</Navbar.Brand>
           </Navbar.Header>
           <DatasetModal show={this.state.isModalOpen} onHide={this.onClose} />
           <Nav>
@@ -116,7 +118,7 @@ class SubMenu extends React.PureComponent<SubMenuProps, 
SubMenuState> {
                 </MenuItem>
               ))}
           </Nav>
-          {this.props.canCreate && (
+          {this.props.canCreate && this.props.createButton && (
             <Nav className="navbar-right">
               <Button onClick={this.onOpen}>
                 <i className="fa fa-plus" /> {this.props.createButton.name}
diff --git a/superset-frontend/src/components/Pagination.tsx 
b/superset-frontend/src/components/Pagination.tsx
new file mode 100644
index 0000000..a023f09
--- /dev/null
+++ b/superset-frontend/src/components/Pagination.tsx
@@ -0,0 +1,132 @@
+/**
+ * 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 React, { PureComponent } from 'react';
+import cx from 'classnames';
+import styled from '@superset-ui/style';
+
+interface PaginationButton {
+  disabled?: boolean;
+  onClick: React.EventHandler<React.SyntheticEvent<HTMLElement>>;
+}
+
+interface PaginationItemButton extends PaginationButton {
+  active: boolean;
+  children: React.ReactNode;
+}
+
+function Prev({ disabled, onClick }: PaginationButton) {
+  return (
+    <li className={cx({ disabled })}>
+      <span role="button" tabIndex={disabled ? -1 : 0} onClick={onClick}>
+        «
+      </span>
+    </li>
+  );
+}
+
+function Next({ disabled, onClick }: PaginationButton) {
+  return (
+    <li className={cx({ disabled })}>
+      <span role="button" tabIndex={disabled ? -1 : 0} onClick={onClick}>
+        »
+      </span>
+    </li>
+  );
+}
+
+function Item({ active, children, onClick }: PaginationItemButton) {
+  return (
+    <li className={cx({ active })}>
+      <span role="button" tabIndex={active ? -1 : 0} onClick={onClick}>
+        {children}
+      </span>
+    </li>
+  );
+}
+
+function Ellipsis({ disabled, onClick }: PaginationButton) {
+  return (
+    <li className={cx({ disabled })}>
+      <span role="button" tabIndex={disabled ? -1 : 0} onClick={onClick}>
+        …
+      </span>
+    </li>
+  );
+}
+
+interface PaginationProps {
+  children: React.ReactNode;
+}
+
+const PaginationList = styled.ul`
+  display: inline-block;
+  margin: 16px 0;
+
+  li {
+    display: inline;
+    margin: 0 4px;
+
+    span {
+      padding: 8px 12px;
+      text-decoration: none;
+      background-color: ${({ theme }) => theme.colors.grayscale.light5};
+      border-radius: ${({ theme }) => theme.borderRadius}px;
+
+      &:hover,
+      &:focus {
+        z-index: 2;
+        color: ${({ theme }) => theme.colors.grayscale.dark1};
+        background-color: ${({ theme }) => theme.colors.grayscale.light3};
+      }
+    }
+
+    &.disabled {
+      span {
+        background-color: transparent;
+        cursor: default;
+
+        &:focus {
+          outline: none;
+        }
+      }
+    }
+    &.active {
+      span {
+        z-index: 3;
+        color: ${({ theme }) => theme.colors.grayscale.light5};
+        cursor: default;
+        background-color: ${({ theme }) => theme.colors.primary.base};
+
+        &:focus {
+          outline: none;
+        }
+      }
+    }
+  }
+`;
+
+export default class Pagination extends PureComponent<PaginationProps> {
+  static Next = Next;
+  static Prev = Prev;
+  static Item = Item;
+  static Ellipsis = Ellipsis;
+  render() {
+    return <PaginationList> {this.props.children}</PaginationList>;
+  }
+}
diff --git a/superset-frontend/src/types/react-table-config.d.ts 
b/superset-frontend/src/types/react-table-config.d.ts
index 5c2321a..63e9d30 100644
--- a/superset-frontend/src/types/react-table-config.d.ts
+++ b/superset-frontend/src/types/react-table-config.d.ts
@@ -64,8 +64,10 @@ import {
   UseSortByOptions,
   UseSortByState,
 } from 'react-table';
+import { ColumnSizer } from 'react-virtualized';
 
 declare module 'react-table' {
+  type ColumnSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
   export interface TableOptions<D extends object>
     extends UseExpandedOptions<D>,
       UseFiltersOptions<D>,
@@ -118,13 +120,19 @@ declare module 'react-table' {
     hidden?: boolean;
     sortable?: boolean;
     cellProps?: any;
+    size?: ColumnSize;
   }
 
   export interface ColumnInstance<D extends object = {}>
     extends UseFiltersColumnProps<D>,
       UseGroupByColumnProps<D>,
       UseResizeColumnsColumnProps<D>,
-      UseSortByColumnProps<D> {}
+      UseSortByColumnProps<D> {
+    hidden?: boolean;
+    sortable?: boolean;
+    cellProps?: any;
+    size?: ColumnSize;
+  }
 
   export interface Cell<D extends object = {}>
     extends UseGroupByCellProps<D>,
diff --git a/superset-frontend/src/utils/common.js 
b/superset-frontend/src/utils/common.js
index 84ae9a1..bbde35d 100644
--- a/superset-frontend/src/utils/common.js
+++ b/superset-frontend/src/utils/common.js
@@ -23,6 +23,10 @@ import getClientErrorObject from './getClientErrorObject';
 
 export const NULL_STRING = '<NULL>';
 
+// moment time format strings
+export const SHORT_DATE = 'MMM D, YYYY';
+export const SHORT_TIME = 'h:m a';
+
 export function getParamFromQuery(query, param) {
   const vars = query.split('&');
   for (let i = 0; i < vars.length; i += 1) {
diff --git a/superset-frontend/src/views/chartList/ChartList.tsx 
b/superset-frontend/src/views/chartList/ChartList.tsx
index 6ff814f..35bc452 100644
--- a/superset-frontend/src/views/chartList/ChartList.tsx
+++ b/superset-frontend/src/views/chartList/ChartList.tsx
@@ -26,6 +26,7 @@ import rison from 'rison';
 // @ts-ignore
 import { Panel } from 'react-bootstrap';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
+import SubMenu from 'src/components/Menu/SubMenu';
 import ListView from 'src/components/ListView/ListView';
 import {
   FetchDataConfig,
@@ -68,7 +69,7 @@ class ChartList extends React.PureComponent<Props, State> {
     filterOperators: {},
     filters: [],
     lastFetchDataConfig: null,
-    loading: false,
+    loading: true,
     permissions: [],
     sliceCurrentlyEditing: null,
   };
@@ -223,7 +224,7 @@ class ChartList extends React.PureComponent<Props, State> {
           </span>
         );
       },
-      Header: 'Actions',
+      Header: t('Actions'),
       id: 'actions',
     },
   ];
@@ -517,58 +518,54 @@ class ChartList extends React.PureComponent<Props, State> 
{
       sliceCurrentlyEditing,
     } = this.state;
     return (
-      <div className="container welcome">
-        <Panel>
-          <Panel.Body>
-            {sliceCurrentlyEditing && (
-              <PropertiesModal
-                show
-                onHide={this.closeChartEditModal}
-                onSave={this.handleChartUpdated}
-                slice={sliceCurrentlyEditing}
+      <>
+        <SubMenu name={t('Charts')} />
+        {sliceCurrentlyEditing && (
+          <PropertiesModal
+            show
+            onHide={this.closeChartEditModal}
+            onSave={this.handleChartUpdated}
+            slice={sliceCurrentlyEditing}
+          />
+        )}
+        <ConfirmStatusChange
+          title={t('Please confirm')}
+          description={t(
+            'Are you sure you want to delete the selected charts?',
+          )}
+          onConfirm={this.handleBulkChartDelete}
+        >
+          {confirmDelete => {
+            const bulkActions = [];
+            if (this.canDelete) {
+              bulkActions.push({
+                key: 'delete',
+                name: (
+                  <>
+                    <i className="fa fa-trash" /> {t('Delete')}
+                  </>
+                ),
+                onSelect: confirmDelete,
+              });
+            }
+            return (
+              <ListView
+                className="chart-list-view"
+                columns={this.columns}
+                data={charts}
+                count={chartCount}
+                pageSize={PAGE_SIZE}
+                fetchData={this.fetchData}
+                loading={loading}
+                initialSort={this.initialSort}
+                filters={filters}
+                bulkActions={bulkActions}
+                useNewUIFilters={this.isNewUIEnabled}
               />
-            )}
-            <ConfirmStatusChange
-              title={t('Please confirm')}
-              description={t(
-                'Are you sure you want to delete the selected charts?',
-              )}
-              onConfirm={this.handleBulkChartDelete}
-            >
-              {confirmDelete => {
-                const bulkActions = [];
-                if (this.canDelete) {
-                  bulkActions.push({
-                    key: 'delete',
-                    name: (
-                      <>
-                        <i className="fa fa-trash" /> Delete
-                      </>
-                    ),
-                    onSelect: confirmDelete,
-                  });
-                }
-                return (
-                  <ListView
-                    className="chart-list-view"
-                    title={'Charts'}
-                    columns={this.columns}
-                    data={charts}
-                    count={chartCount}
-                    pageSize={PAGE_SIZE}
-                    fetchData={this.fetchData}
-                    loading={loading}
-                    initialSort={this.initialSort}
-                    filters={filters}
-                    bulkActions={bulkActions}
-                    useNewUIFilters={this.isNewUIEnabled}
-                  />
-                );
-              }}
-            </ConfirmStatusChange>
-          </Panel.Body>
-        </Panel>
-      </div>
+            );
+          }}
+        </ConfirmStatusChange>
+      </>
     );
   }
 }
diff --git a/superset-frontend/src/views/dashboardList/DashboardList.tsx 
b/superset-frontend/src/views/dashboardList/DashboardList.tsx
index 0fba528..50e8bc9 100644
--- a/superset-frontend/src/views/dashboardList/DashboardList.tsx
+++ b/superset-frontend/src/views/dashboardList/DashboardList.tsx
@@ -25,6 +25,7 @@ import rison from 'rison';
 // @ts-ignore
 import { Panel } from 'react-bootstrap';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
+import SubMenu from 'src/components/Menu/SubMenu';
 import ListView from 'src/components/ListView/ListView';
 import ExpandableList from 'src/components/ExpandableList';
 import {
@@ -76,7 +77,7 @@ class DashboardList extends React.PureComponent<Props, State> 
{
     filterOperators: {},
     filters: [],
     lastFetchDataConfig: null,
-    loading: false,
+    loading: true,
     permissions: [],
     dashboardToEdit: null,
   };
@@ -508,71 +509,67 @@ class DashboardList extends React.PureComponent<Props, 
State> {
       dashboardToEdit,
     } = this.state;
     return (
-      <div className="container welcome">
-        <Panel>
-          <Panel.Body>
-            <ConfirmStatusChange
-              title={t('Please confirm')}
-              description={t(
-                'Are you sure you want to delete the selected dashboards?',
-              )}
-              onConfirm={this.handleBulkDashboardDelete}
-            >
-              {confirmDelete => {
-                const bulkActions = [];
-                if (this.canDelete) {
-                  bulkActions.push({
-                    key: 'delete',
-                    name: (
-                      <>
-                        <i className="fa fa-trash" /> Delete
-                      </>
-                    ),
-                    onSelect: confirmDelete,
-                  });
-                }
-                if (this.canExport) {
-                  bulkActions.push({
-                    key: 'export',
-                    name: (
-                      <>
-                        <i className="fa fa-database" /> Export
-                      </>
-                    ),
-                    onSelect: this.handleBulkDashboardExport,
-                  });
-                }
-                return (
+      <>
+        <SubMenu name={t('Dashboards')} />
+        <ConfirmStatusChange
+          title={t('Please confirm')}
+          description={t(
+            'Are you sure you want to delete the selected dashboards?',
+          )}
+          onConfirm={this.handleBulkDashboardDelete}
+        >
+          {confirmDelete => {
+            const bulkActions = [];
+            if (this.canDelete) {
+              bulkActions.push({
+                key: 'delete',
+                name: (
+                  <>
+                    <i className="fa fa-trash" /> {t('Delete')}
+                  </>
+                ),
+                onSelect: confirmDelete,
+              });
+            }
+            if (this.canExport) {
+              bulkActions.push({
+                key: 'export',
+                name: (
                   <>
-                    {dashboardToEdit && (
-                      <PropertiesModal
-                        show
-                        dashboardId={dashboardToEdit.id}
-                        onHide={() => this.setState({ dashboardToEdit: null })}
-                        onDashboardSave={this.handleDashboardEdit}
-                      />
-                    )}
-                    <ListView
-                      className="dashboard-list-view"
-                      title={'Dashboards'}
-                      columns={this.columns}
-                      data={dashboards}
-                      count={dashboardCount}
-                      pageSize={PAGE_SIZE}
-                      fetchData={this.fetchData}
-                      loading={loading}
-                      initialSort={this.initialSort}
-                      filters={filters}
-                      bulkActions={bulkActions}
-                      useNewUIFilters={this.isNewUIEnabled}
-                    />
+                    <i className="fa fa-database" /> {t('Export')}
                   </>
-                );
-              }}
-            </ConfirmStatusChange>
-          </Panel.Body>
-        </Panel>
-      </div>
+                ),
+                onSelect: this.handleBulkDashboardExport,
+              });
+            }
+            return (
+              <>
+                {dashboardToEdit && (
+                  <PropertiesModal
+                    show
+                    dashboardId={dashboardToEdit.id}
+                    onHide={() => this.setState({ dashboardToEdit: null })}
+                    onDashboardSave={this.handleDashboardEdit}
+                  />
+                )}
+                <ListView
+                  className="dashboard-list-view"
+                  columns={this.columns}
+                  data={dashboards}
+                  count={dashboardCount}
+                  pageSize={PAGE_SIZE}
+                  fetchData={this.fetchData}
+                  loading={loading}
+                  initialSort={this.initialSort}
+                  filters={filters}
+                  bulkActions={bulkActions}
+                  useNewUIFilters={this.isNewUIEnabled}
+                />
+              </>
+            );
+          }}
+        </ConfirmStatusChange>
+      </>
     );
   }
 }
diff --git a/superset-frontend/src/views/datasetList/DatasetList.tsx 
b/superset-frontend/src/views/datasetList/DatasetList.tsx
index ae0c5a3..a4ee407 100644
--- a/superset-frontend/src/views/datasetList/DatasetList.tsx
+++ b/superset-frontend/src/views/datasetList/DatasetList.tsx
@@ -24,6 +24,7 @@ import React from 'react';
 import rison from 'rison';
 // @ts-ignore
 import { Panel } from 'react-bootstrap';
+import { SHORT_DATE, SHORT_TIME } from 'src/utils/common';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import ListView from 'src/components/ListView/ListView';
 import SubMenu from 'src/components/Menu/SubMenu';
@@ -87,7 +88,7 @@ class DatasetList extends React.PureComponent<Props, State> {
     filterOperators: {},
     filters: [],
     lastFetchDataConfig: null,
-    loading: false,
+    loading: true,
     owners: [],
     databases: [],
     permissions: [],
@@ -175,6 +176,7 @@ class DatasetList extends React.PureComponent<Props, State> 
{
         );
       },
       accessor: 'kind_icon',
+      size: 'xs',
     },
     {
       Cell: ({
@@ -184,6 +186,7 @@ class DatasetList extends React.PureComponent<Props, State> 
{
       }: any) => datasetTitle,
       Header: t('Name'),
       accessor: 'table_name',
+      sortable: true,
     },
     {
       Cell: ({
@@ -193,36 +196,51 @@ class DatasetList extends React.PureComponent<Props, 
State> {
       }: any) => kind[0]?.toUpperCase() + kind.slice(1),
       Header: t('Type'),
       accessor: 'kind',
+      size: 'md',
     },
     {
       Header: t('Source'),
       accessor: 'database_name',
+      size: 'lg',
     },
     {
       Header: t('Schema'),
       accessor: 'schema',
+      size: 'lg',
     },
     {
       Cell: ({
         row: {
           original: { changed_on: changedOn },
         },
-      }: any) => <span 
className="no-wrap">{moment(changedOn).fromNow()}</span>,
+      }: any) => {
+        const momentTime = moment(changedOn);
+        const time = momentTime.format(SHORT_DATE);
+        const date = momentTime.format(SHORT_TIME);
+        return (
+          <TooltipWrapper
+            label="last-modified"
+            tooltip={time}
+            placement="right"
+          >
+            <span>{date}</span>
+          </TooltipWrapper>
+        );
+      },
       Header: t('Last Modified'),
       accessor: 'changed_on',
       sortable: true,
+      size: 'xl',
     },
     {
       Cell: ({
         row: {
-          original: {
-            changed_by_name: changedByName,
-            changed_by_url: changedByUrl,
-          },
+          original: { changed_by_name: changedByName },
         },
-      }: any) => <a href={changedByUrl}>{changedByName}</a>,
+      }: any) => changedByName,
       Header: t('Modified By'),
       accessor: 'changed_by_fk',
+      size: 'xl',
     },
     {
       accessor: 'database',
@@ -241,16 +259,19 @@ class DatasetList extends React.PureComponent<Props, 
State> {
           .slice(0, 5)
           .map((owner: Owner) => (
             <AvatarIcon
+              key={owner.id}
               tableName={tableName}
               firstName={owner.first_name}
               lastName={owner.last_name}
               userName={owner.username}
-              iconSize="20"
+              iconSize={24}
+              textSize={9}
             />
           ));
       },
       Header: t('Owners'),
       id: 'owners',
+      size: 'lg',
     },
     {
       accessor: 'is_sqllab_view',
@@ -267,14 +288,20 @@ class DatasetList extends React.PureComponent<Props, 
State> {
           <span
             className={`actions ${state && state.hover ? '' : 'invisible'}`}
           >
-            <a
-              role="button"
-              tabIndex={0}
-              className="action-button"
-              href={original.explore_url}
+            <TooltipWrapper
+              label="explore-action"
+              tooltip={t('Explore')}
+              placement="bottom"
             >
-              <Icon name="compass" />
-            </a>
+              <a
+                role="button"
+                tabIndex={0}
+                className="action-button"
+                href={original.explore_url}
+              >
+                <Icon name="compass" />
+              </a>
+            </TooltipWrapper>
             {this.canDelete && (
               <ConfirmStatusChange
                 title={t('Please Confirm')}
@@ -287,26 +314,38 @@ class DatasetList extends React.PureComponent<Props, 
State> {
                 onConfirm={handleDelete}
               >
                 {confirmDelete => (
-                  <span
-                    role="button"
-                    tabIndex={0}
-                    className="action-button"
-                    onClick={confirmDelete}
+                  <TooltipWrapper
+                    label="delete-action"
+                    tooltip={t('Delete')}
+                    placement="bottom"
                   >
-                    <Icon name="trash" />
-                  </span>
+                    <span
+                      role="button"
+                      tabIndex={0}
+                      className="action-button"
+                      onClick={confirmDelete}
+                    >
+                      <Icon name="trash" />
+                    </span>
+                  </TooltipWrapper>
                 )}
               </ConfirmStatusChange>
             )}
             {this.canEdit && (
-              <span
-                role="button"
-                tabIndex={0}
-                className="action-button"
-                onClick={handleEdit}
+              <TooltipWrapper
+                label="edit-action"
+                tooltip={t('Edit')}
+                placement="bottom"
               >
-                <Icon name="pencil" />
-              </span>
+                <span
+                  role="button"
+                  tabIndex={0}
+                  className="action-button"
+                  onClick={handleEdit}
+                >
+                  <Icon name="pencil" />
+                </span>
+              </TooltipWrapper>
             )}
           </span>
         );
@@ -317,8 +356,7 @@ class DatasetList extends React.PureComponent<Props, State> 
{
   ];
 
   menu = {
-    label: 'Data',
-    name: 'Data',
+    name: t('Data'),
     createButton: {
       name: t('Dataset'),
       url: '/tablemodelview/add',
@@ -487,49 +525,42 @@ class DatasetList extends React.PureComponent<Props, 
State> {
     return (
       <>
         <SubMenu {...this.menu} canCreate={this.canCreate} />
-        <div className="container welcome">
-          <Panel>
-            <Panel.Body>
-              <ConfirmStatusChange
-                title={t('Please confirm')}
-                description={t(
-                  'Are you sure you want to delete the selected datasets?',
-                )}
-                onConfirm={this.handleBulkDatasetDelete}
-              >
-                {confirmDelete => {
-                  const bulkActions = [];
-                  if (this.canDelete) {
-                    bulkActions.push({
-                      key: 'delete',
-                      name: (
-                        <>
-                          <i className="fa fa-trash" /> Delete
-                        </>
-                      ),
-                      onSelect: confirmDelete,
-                    });
-                  }
-                  return (
-                    <ListView
-                      className="dataset-list-view"
-                      title={'Datasets'}
-                      columns={this.columns}
-                      data={datasets}
-                      count={datasetCount}
-                      pageSize={PAGE_SIZE}
-                      fetchData={this.fetchData}
-                      loading={loading}
-                      initialSort={this.initialSort}
-                      filters={filters}
-                      bulkActions={bulkActions}
-                    />
-                  );
-                }}
-              </ConfirmStatusChange>
-            </Panel.Body>
-          </Panel>
-        </div>
+        <ConfirmStatusChange
+          title={t('Please confirm')}
+          description={t(
+            'Are you sure you want to delete the selected datasets?',
+          )}
+          onConfirm={this.handleBulkDatasetDelete}
+        >
+          {confirmDelete => {
+            const bulkActions = [];
+            if (this.canDelete) {
+              bulkActions.push({
+                key: 'delete',
+                name: (
+                  <>
+                    <i className="fa fa-trash" /> {t('Delete')}
+                  </>
+                ),
+                onSelect: confirmDelete,
+              });
+            }
+            return (
+              <ListView
+                className="dataset-list-view"
+                columns={this.columns}
+                data={datasets}
+                count={datasetCount}
+                pageSize={PAGE_SIZE}
+                fetchData={this.fetchData}
+                loading={loading}
+                initialSort={this.initialSort}
+                filters={filters}
+                bulkActions={bulkActions}
+              />
+            );
+          }}
+        </ConfirmStatusChange>
       </>
     );
   }
diff --git a/superset-frontend/stylesheets/less/variables.less 
b/superset-frontend/stylesheets/less/variables.less
index f22db91..5f01c94 100644
--- a/superset-frontend/stylesheets/less/variables.less
+++ b/superset-frontend/stylesheets/less/variables.less
@@ -209,8 +209,4 @@
 /* in favor of custom/reusable CSS wherever possible                    */
 /************************************************************************/
 
-// ***************************** SIP 34 UI *******************************
-@table-hover: rgba(236, 238, 242, 0.5);
-@table-selected: #eceef2;
-
 @import '../less/cosmo/variables.less';

Reply via email to