michael-s-molina commented on code in PR #21520:
URL: https://github.com/apache/superset/pull/21520#discussion_r1015980277


##########
superset-frontend/src/components/MetadataBar/MetadataBar.stories.mdx:
##########
@@ -1,17 +1,25 @@
-import { Meta, Source } from '@storybook/addon-docs';
+import { Meta, Source, Story } from '@storybook/addon-docs';
 
-<Meta title="MetadataBar/Overview" />
+<Meta title="Design System/Components/MetadataBar/Overview" />
 
-# Usage
+# Metadata bar
 
-The metadata bar component is used to display additional information about an 
entity. Some of the common applications in Superset are:
+The metadata bar component is used to display additional information about an 
entity.
+
+## Usage
+
+Some of the common applications in Superset are:
 
 - Display the chart's metadata in Explore to help the user understand what 
dashboards this chart is added to and get
   to know the details of the chart
 - Display the database's metadata in a drill to detail modal to help the user 
understand what data they are looking
   at while accessing the feature in the dashboard
 
-# Variations
+## Basic example
+
+<Story id="design-system-components-metadatabar-examples--basic" />

Review Comment:
   You need to update the link to the component page on line 36 to 
`[MetadataBar](/story/design-system-components-metadatabar-examples--basic)`



##########
superset-frontend/src/components/Table/Table.overview.mdx:
##########
@@ -0,0 +1,260 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Overview" />
+
+# Table
+
+A table is UI that allows the user to explore data in a tabular format.
+
+## Usage
+
+Common table applications in Superset:
+
+- Display lists of user-generated entities (e.g. dashboard, charts, queries) 
for further exploration and use
+- Display data that can help the user make a decision (e.g. query results)
+
+This component provides a general use Table.
+
+---
+
+### [Basic 
example](./?path=/docs/design-system-components-table-examples--basic)
+
+<Story id="design-system-components-table-examples--basic" />
+
+### Data and Columns
+
+To set the visible columns and data for the table you use the `columns` and 
`data` props.
+
+<details>
+
+The basic table example for the `columns` prop is:
+
+```
+const basicColumns: = [
+  {
+    title: 'Name',
+    dataIndex: 'name',
+    key: 'name',
+    width: 150,
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('name', a, b),
+  },
+  {
+    title: 'Category',
+    dataIndex: 'category',
+    key: 'category',
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('category', a, b),
+  },
+  {
+    title: 'Price',
+    dataIndex: 'price',
+    key: 'price',
+    sorter: (a: BasicData, b: BasicData) =>
+      numericalSort('price', a, b),
+  },
+  {
+    title: 'Description',
+    dataIndex: 'description',
+    key: 'description',
+  },
+];
+```
+
+The data prop is:
+
+```
+const basicData: = [
+  {
+    key: 1,
+    name: 'Floppy Disk 10 pack',
+    category: 'Disk Storage',
+    price: '9.99'
+    description: 'A real blast from the past',
+  },
+  {
+    key: 2,
+    name: 'DVD 100 pack',
+    category: 'Optical Storage',
+    price: '27.99'
+    description: 'Still pretty ancient',
+  },
+  {
+    key: 3,
+    name: '128 GB SSD',
+    category: 'Hardrive',
+    price: '49.99'
+    description: 'Reliable and fast data storage',
+  },
+];
+```
+
+</details>
+
+### Column Sort Functions
+
+To ensure consistency for column sorting and to avoid redundant definitions 
for common column sorters, reusable sort functions are provided.
+When defining the object for the `columns` prop you can provide an optional 
attribute `sorter`.
+The function provided in the `sorter` prop is given the entire record 
representing a row as props `a` and `b`.
+When using a provided sorter function the pattern is to wrap the call to the 
sorter with an inline function, then specify the specific attribute value from 
`dataIndex`, representing a column
+of the data object for that row, as the first argument of the sorter function.
+
+#### alphabeticalSort
+
+The alphabeticalSort is for columns that display a string of text.
+
+<details>
+
+```
+import { alphabeticalSort } from 'src/components/Table/sorters';
+
+const basicColumns = [
+  {
+    title: 'Column Name',
+    dataIndex: 'columnName',
+    key: 'columnName',
+    sorter: (a, b) =>
+      alphabeticalSort('columnName', a, b),
+  }
+]
+```
+
+</details>
+
+#### numericSort
+
+The numericalSort is for columns that display a numeric value.
+
+<details>
+
+```
+import { numericalSort } from './sorters';
+
+const basicColumns = [
+  {
+    title: 'Height',
+    dataIndex: 'height',
+    key: 'height',
+    sorter: (a, b) =>
+      numericalSort('height', a, b),
+  }
+]
+```
+
+</details>
+
+If a different sort option is needed, consider adding it as a re-usable sort 
function following the pattern provided above.

Review Comment:
   ```suggestion
   If a different sort option is needed, consider adding it as a reusable sort 
function following the pattern provided above.
   ```



##########
superset-frontend/src/components/Table/Table.overview.mdx:
##########
@@ -0,0 +1,260 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Overview" />
+
+# Table
+
+A table is UI that allows the user to explore data in a tabular format.
+
+## Usage
+
+Common table applications in Superset:
+
+- Display lists of user-generated entities (e.g. dashboard, charts, queries) 
for further exploration and use
+- Display data that can help the user make a decision (e.g. query results)
+
+This component provides a general use Table.
+
+---
+
+### [Basic 
example](./?path=/docs/design-system-components-table-examples--basic)
+
+<Story id="design-system-components-table-examples--basic" />
+
+### Data and Columns
+
+To set the visible columns and data for the table you use the `columns` and 
`data` props.
+
+<details>
+
+The basic table example for the `columns` prop is:
+
+```
+const basicColumns: = [
+  {
+    title: 'Name',
+    dataIndex: 'name',
+    key: 'name',
+    width: 150,
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('name', a, b),
+  },
+  {
+    title: 'Category',
+    dataIndex: 'category',
+    key: 'category',
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('category', a, b),
+  },
+  {
+    title: 'Price',
+    dataIndex: 'price',
+    key: 'price',
+    sorter: (a: BasicData, b: BasicData) =>
+      numericalSort('price', a, b),
+  },
+  {
+    title: 'Description',
+    dataIndex: 'description',
+    key: 'description',
+  },
+];
+```
+
+The data prop is:
+
+```
+const basicData: = [
+  {
+    key: 1,
+    name: 'Floppy Disk 10 pack',
+    category: 'Disk Storage',
+    price: '9.99'
+    description: 'A real blast from the past',
+  },
+  {
+    key: 2,
+    name: 'DVD 100 pack',
+    category: 'Optical Storage',
+    price: '27.99'
+    description: 'Still pretty ancient',
+  },
+  {
+    key: 3,
+    name: '128 GB SSD',
+    category: 'Hardrive',
+    price: '49.99'
+    description: 'Reliable and fast data storage',
+  },
+];
+```
+
+</details>
+
+### Column Sort Functions
+
+To ensure consistency for column sorting and to avoid redundant definitions 
for common column sorters, reusable sort functions are provided.
+When defining the object for the `columns` prop you can provide an optional 
attribute `sorter`.
+The function provided in the `sorter` prop is given the entire record 
representing a row as props `a` and `b`.
+When using a provided sorter function the pattern is to wrap the call to the 
sorter with an inline function, then specify the specific attribute value from 
`dataIndex`, representing a column
+of the data object for that row, as the first argument of the sorter function.
+
+#### alphabeticalSort
+
+The alphabeticalSort is for columns that display a string of text.
+
+<details>
+
+```
+import { alphabeticalSort } from 'src/components/Table/sorters';
+
+const basicColumns = [
+  {
+    title: 'Column Name',
+    dataIndex: 'columnName',
+    key: 'columnName',
+    sorter: (a, b) =>
+      alphabeticalSort('columnName', a, b),
+  }
+]
+```
+
+</details>
+
+#### numericSort
+
+The numericalSort is for columns that display a numeric value.
+
+<details>
+
+```
+import { numericalSort } from './sorters';
+
+const basicColumns = [
+  {
+    title: 'Height',
+    dataIndex: 'height',
+    key: 'height',
+    sorter: (a, b) =>
+      numericalSort('height', a, b),
+  }
+]
+```
+
+</details>
+
+If a different sort option is needed, consider adding it as a re-usable sort 
function following the pattern provided above.
+
+---
+
+### Cell Content Renderers
+
+By default each column will render the value as simple text. Often you will 
want to show formatted values, such as a numeric column showing as currency, or 
a more complex component such as a button or action menu as a cell value.
+Cell Renderers are React components provided to the optional `render` 
attribute on a column definition that enables injecting a specific React 
component to enable this.
+
+<Story id="design-system-components-table-examples--cell-renderers" />
+
+For convenience and consistency, the Table component provides pre-built Cell 
Renderers for:
+The following data types can be displayed in table cells.
+
+- Text (default)
+- [Button 
Cell](./?path=/docs/design-system-components-table-cell-renderers-buttoncell--basic)
+- [Numeric 
Cell](./docs/design-system-components-table-cell-renderers-numericcell--basic)
+  - Support Locale and currency formatting
+  - w/ icons - Coming Soon
+- [Action Menu 
Cell](./?path=/docs/design-system-components-table-cell-renderers-actioncell-overview--page)
+- Provide a list of menu options with callback functions that retain a 
reference to the row the menu is defined for
+- Custom
+  - You can provide your own React component as a cell renderer in cases not 
supported
+
+---
+
+### Loading
+
+The table can be set to a loading state simply by setting the loading prop to 
true | false
+
+<Story id="design-system-components-table-examples--loading" />
+
+---
+
+### Pagination
+
+Table displays set number of rows at a time, user navigates table via 
pagination. Use in scenarios where the user is searching for a specific piece 
of content.
+The default page size and page size options for menu are configurable via the 
`pageSizeOptions` and `defaultPageSize` props.

Review Comment:
   ```suggestion
   The default page size and page size options for the menu are configurable 
via the `pageSizeOptions` and `defaultPageSize` props.
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.test.tsx:
##########
@@ -0,0 +1,49 @@
+/**
+ * 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 from 'react';
+import { render, screen } from 'spec/helpers/testing-library';
+import { configure } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import ActionCell, { appendDataToMenu } from './index';
+import { exampleMenuOptions, exampleRow } from './fixtures';
+
+test('renders with default props', async () => {
+  configure({ testIdAttribute: 'data-test' });

Review Comment:
   This is already set in `spec/helpers/setup.ts`
   
   ```suggestion
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.test.tsx:
##########
@@ -0,0 +1,43 @@
+/**
+ * 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 from 'react';
+import { render, screen } from 'spec/helpers/testing-library';
+import { configure } from '@testing-library/react';

Review Comment:
   ```suggestion
   ```



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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.
+ */
+

Review Comment:
   We generally don't leave a blank line after the license. It's not a blocker 
for me, but if you choose to remove it to keep the codebase consistent then you 
can update the other files.



##########
superset-frontend/src/components/Table/Table.overview.mdx:
##########
@@ -0,0 +1,260 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Overview" />
+
+# Table
+
+A table is UI that allows the user to explore data in a tabular format.
+
+## Usage
+
+Common table applications in Superset:
+
+- Display lists of user-generated entities (e.g. dashboard, charts, queries) 
for further exploration and use
+- Display data that can help the user make a decision (e.g. query results)
+
+This component provides a general use Table.
+
+---
+
+### [Basic 
example](./?path=/docs/design-system-components-table-examples--basic)
+
+<Story id="design-system-components-table-examples--basic" />
+
+### Data and Columns
+
+To set the visible columns and data for the table you use the `columns` and 
`data` props.
+
+<details>
+
+The basic table example for the `columns` prop is:
+
+```
+const basicColumns: = [
+  {
+    title: 'Name',
+    dataIndex: 'name',
+    key: 'name',
+    width: 150,
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('name', a, b),
+  },
+  {
+    title: 'Category',
+    dataIndex: 'category',
+    key: 'category',
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('category', a, b),
+  },
+  {
+    title: 'Price',
+    dataIndex: 'price',
+    key: 'price',
+    sorter: (a: BasicData, b: BasicData) =>
+      numericalSort('price', a, b),
+  },
+  {
+    title: 'Description',
+    dataIndex: 'description',
+    key: 'description',
+  },
+];
+```
+
+The data prop is:
+
+```
+const basicData: = [
+  {
+    key: 1,
+    name: 'Floppy Disk 10 pack',
+    category: 'Disk Storage',
+    price: '9.99'
+    description: 'A real blast from the past',
+  },
+  {
+    key: 2,
+    name: 'DVD 100 pack',
+    category: 'Optical Storage',
+    price: '27.99'
+    description: 'Still pretty ancient',
+  },
+  {
+    key: 3,
+    name: '128 GB SSD',
+    category: 'Hardrive',
+    price: '49.99'
+    description: 'Reliable and fast data storage',
+  },
+];
+```
+
+</details>
+
+### Column Sort Functions
+
+To ensure consistency for column sorting and to avoid redundant definitions 
for common column sorters, reusable sort functions are provided.
+When defining the object for the `columns` prop you can provide an optional 
attribute `sorter`.
+The function provided in the `sorter` prop is given the entire record 
representing a row as props `a` and `b`.
+When using a provided sorter function the pattern is to wrap the call to the 
sorter with an inline function, then specify the specific attribute value from 
`dataIndex`, representing a column
+of the data object for that row, as the first argument of the sorter function.
+
+#### alphabeticalSort
+
+The alphabeticalSort is for columns that display a string of text.
+
+<details>
+
+```
+import { alphabeticalSort } from 'src/components/Table/sorters';
+
+const basicColumns = [
+  {
+    title: 'Column Name',
+    dataIndex: 'columnName',
+    key: 'columnName',
+    sorter: (a, b) =>
+      alphabeticalSort('columnName', a, b),
+  }
+]
+```
+
+</details>
+
+#### numericSort
+
+The numericalSort is for columns that display a numeric value.
+
+<details>
+
+```
+import { numericalSort } from './sorters';
+
+const basicColumns = [
+  {
+    title: 'Height',
+    dataIndex: 'height',
+    key: 'height',
+    sorter: (a, b) =>
+      numericalSort('height', a, b),
+  }
+]
+```
+
+</details>
+
+If a different sort option is needed, consider adding it as a re-usable sort 
function following the pattern provided above.
+
+---
+
+### Cell Content Renderers
+
+By default each column will render the value as simple text. Often you will 
want to show formatted values, such as a numeric column showing as currency, or 
a more complex component such as a button or action menu as a cell value.
+Cell Renderers are React components provided to the optional `render` 
attribute on a column definition that enables injecting a specific React 
component to enable this.
+
+<Story id="design-system-components-table-examples--cell-renderers" />
+
+For convenience and consistency, the Table component provides pre-built Cell 
Renderers for:
+The following data types can be displayed in table cells.
+
+- Text (default)
+- [Button 
Cell](./?path=/docs/design-system-components-table-cell-renderers-buttoncell--basic)
+- [Numeric 
Cell](./docs/design-system-components-table-cell-renderers-numericcell--basic)
+  - Support Locale and currency formatting
+  - w/ icons - Coming Soon
+- [Action Menu 
Cell](./?path=/docs/design-system-components-table-cell-renderers-actioncell-overview--page)
+- Provide a list of menu options with callback functions that retain a 
reference to the row the menu is defined for
+- Custom
+  - You can provide your own React component as a cell renderer in cases not 
supported
+
+---
+
+### Loading
+
+The table can be set to a loading state simply by setting the loading prop to 
true | false
+
+<Story id="design-system-components-table-examples--loading" />
+
+---
+
+### Pagination
+
+Table displays set number of rows at a time, user navigates table via 
pagination. Use in scenarios where the user is searching for a specific piece 
of content.

Review Comment:
   ```suggestion
   The table displays a set number of rows at a time, the user navigates the 
table via pagination. Use in scenarios where the user is searching for a 
specific piece of content.
   ```



##########
superset-frontend/src/components/Table/Table.overview.mdx:
##########
@@ -0,0 +1,260 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Overview" />
+
+# Table
+
+A table is UI that allows the user to explore data in a tabular format.
+
+## Usage
+
+Common table applications in Superset:
+
+- Display lists of user-generated entities (e.g. dashboard, charts, queries) 
for further exploration and use
+- Display data that can help the user make a decision (e.g. query results)
+
+This component provides a general use Table.
+
+---
+
+### [Basic 
example](./?path=/docs/design-system-components-table-examples--basic)
+
+<Story id="design-system-components-table-examples--basic" />
+
+### Data and Columns
+
+To set the visible columns and data for the table you use the `columns` and 
`data` props.
+
+<details>
+
+The basic table example for the `columns` prop is:
+
+```
+const basicColumns: = [
+  {
+    title: 'Name',
+    dataIndex: 'name',
+    key: 'name',
+    width: 150,
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('name', a, b),
+  },
+  {
+    title: 'Category',
+    dataIndex: 'category',
+    key: 'category',
+    sorter: (a: BasicData, b: BasicData) =>
+      alphabeticalSort('category', a, b),
+  },
+  {
+    title: 'Price',
+    dataIndex: 'price',
+    key: 'price',
+    sorter: (a: BasicData, b: BasicData) =>
+      numericalSort('price', a, b),
+  },
+  {
+    title: 'Description',
+    dataIndex: 'description',
+    key: 'description',
+  },
+];
+```
+
+The data prop is:
+
+```
+const basicData: = [
+  {
+    key: 1,
+    name: 'Floppy Disk 10 pack',
+    category: 'Disk Storage',
+    price: '9.99'
+    description: 'A real blast from the past',
+  },
+  {
+    key: 2,
+    name: 'DVD 100 pack',
+    category: 'Optical Storage',
+    price: '27.99'
+    description: 'Still pretty ancient',
+  },
+  {
+    key: 3,
+    name: '128 GB SSD',
+    category: 'Hardrive',
+    price: '49.99'
+    description: 'Reliable and fast data storage',
+  },
+];
+```
+
+</details>
+
+### Column Sort Functions
+
+To ensure consistency for column sorting and to avoid redundant definitions 
for common column sorters, reusable sort functions are provided.
+When defining the object for the `columns` prop you can provide an optional 
attribute `sorter`.
+The function provided in the `sorter` prop is given the entire record 
representing a row as props `a` and `b`.
+When using a provided sorter function the pattern is to wrap the call to the 
sorter with an inline function, then specify the specific attribute value from 
`dataIndex`, representing a column
+of the data object for that row, as the first argument of the sorter function.
+
+#### alphabeticalSort
+
+The alphabeticalSort is for columns that display a string of text.
+
+<details>
+
+```
+import { alphabeticalSort } from 'src/components/Table/sorters';
+
+const basicColumns = [
+  {
+    title: 'Column Name',
+    dataIndex: 'columnName',
+    key: 'columnName',
+    sorter: (a, b) =>
+      alphabeticalSort('columnName', a, b),
+  }
+]
+```
+
+</details>
+
+#### numericSort
+
+The numericalSort is for columns that display a numeric value.
+
+<details>
+
+```
+import { numericalSort } from './sorters';
+
+const basicColumns = [
+  {
+    title: 'Height',
+    dataIndex: 'height',
+    key: 'height',
+    sorter: (a, b) =>
+      numericalSort('height', a, b),
+  }
+]
+```
+
+</details>
+
+If a different sort option is needed, consider adding it as a re-usable sort 
function following the pattern provided above.
+
+---
+
+### Cell Content Renderers
+
+By default each column will render the value as simple text. Often you will 
want to show formatted values, such as a numeric column showing as currency, or 
a more complex component such as a button or action menu as a cell value.

Review Comment:
   ```suggestion
   By default, each column will render the value as simple text. Often you will 
want to show formatted values, such as a numeric column showing as currency, or 
a more complex component such as a button or action menu as a cell value.
   ```



##########
superset-frontend/src/components/DesignSystem.stories.mdx:
##########
@@ -0,0 +1,25 @@
+import { Meta, Source } from '@storybook/addon-docs';
+import AtomicDesign from './atomic-design.png';
+
+<Meta title="Design System/Introduction" />
+
+# Superset Design System
+
+A design system is a complete set of standards intended to manage design at 
scale using reusable components and patterns.
+
+You can get an overview of Atmomic Design concepts and link to full book on 
the topic here:

Review Comment:
   ```suggestion
   You can get an overview of Atomic Design concepts and a link to the full 
book on the topic here:
   ```



##########
superset-frontend/src/components/Dropdown/index.tsx:
##########
@@ -66,14 +67,35 @@ const MenuDotsWrapper = styled.div`
   padding-left: ${({ theme }) => theme.gridUnit}px;
 `;
 
+export enum IconOrientation {
+  VERTICAL = 'vertical',
+  HORIZONTAL = 'horizontal',
+}
 export interface DropdownProps extends DropDownProps {
   overlay: React.ReactElement;
+  orientation?: IconOrientation;

Review Comment:
   The first time I read the property I thought it referred to the orientation 
of the dropdown. Maybe rename it to `iconOrientation`? It would be helpful when 
reading the property from a parent component and the type is not displayed.



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx:
##########
@@ -0,0 +1,69 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Cell 
Renderers/ActionCell/Overview" />
+
+# ActionCell
+
+An ActionCell is used to display overflow icon that opens a menu allowing the 
user to take actions
+specific to the data in the table row that the cell is a member of.

Review Comment:
   ```suggestion
   An ActionCell is used to display an overflow icon that opens a menu allowing 
the user to take actions
   specific to the data in the table row that the cell is a member of.
   ```



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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, { useState, useEffect, useRef, ReactElement } from 'react';
+import { Table as AntTable, ConfigProvider } from 'antd';
+import type { ColumnsType, TableProps as AntTableProps } from 'antd/es/table';
+import { t, useTheme } from '@superset-ui/core';
+import Loading from 'src/components/Loading';
+import styled, { StyledComponent } from '@emotion/styled';
+import InteractiveTableUtils from './utils/InteractiveTableUtils';
+
+export const SUPERSET_TABLE_COLUMN = 'superset/table-column';
+export interface TableDataType {
+  key: React.Key;
+}
+
+export enum SelectionType {
+  'DISABLED' = 'disabled',
+  'SINGLE' = 'single',
+  'MULTI' = 'multi',
+}
+
+export interface Locale {
+  /**
+   * Text contained within the Table UI.
+   */
+  filterTitle: string;
+  filterConfirm: string;
+  filterReset: string;
+  filterEmptyText: string;
+  filterCheckall: string;
+  filterSearchPlaceholder: string;
+  emptyText: string;
+  selectAll: string;
+  selectInvert: string;
+  selectNone: string;
+  selectionAll: string;
+  sortTitle: string;
+  expand: string;
+  collapse: string;
+  triggerDesc: string;
+  triggerAsc: string;
+  cancelSort: string;
+}
+
+export interface TableProps extends AntTableProps<TableProps> {
+  /**
+   * Data that will populate the each row and map to the column key.
+   */
+  data: object[];
+  /**
+   * Table column definitions.
+   */
+  columns: ColumnsType<any>;
+  /**
+   * Array of row keys to represent list of selected rows.
+   */
+  selectedRows?: React.Key[];
+  /**
+   * Callback function invoked when a row is selected by user.
+   */
+  handleRowSelection?: Function;
+  /**
+   * Controls the size of the table.
+   */
+  size: TableSize;
+  /**
+   * Adjusts the padding around elements for different amounts of spacing 
between elements.
+   */
+  selectionType?: SelectionType;
+  /*
+   * Places table in visual loading state.  Use while waiting to retrieve data 
or perform an async operation that will update the table.
+   */
+  loading?: boolean;
+  /**
+   * Uses a sticky header which always displays when vertically scrolling the 
table.  Default: true
+   */
+  sticky?: boolean;
+  /**
+   * Controls if columns are resizable by user.
+   */
+  resizable?: boolean;
+  /**
+   * EXPERIMENTAL: Controls if columns are re-orderable by user drag drop.
+   */
+  reorderable?: boolean;
+  /**
+   * Default number of rows table will display per page of data.
+   */
+  defaultPageSize?: number;
+  /**
+   * Array of numeric options for the number of rows table will display per 
page of data.
+   * The user can select from these options in the page size drop down menu.
+   */
+  pageSizeOptions?: string[];
+  /**
+   * Set table to display no data even if data has been provided
+   */
+  hideData?: boolean;
+  /**
+   * emptyComponent
+   */
+  emptyComponent?: ReactElement;
+  /**
+   * Enables setting the text displayed in various components and tooltips 
within the Table UI.
+   */
+  locale?: Locale;
+  /**
+   * Restricts the visible height of the table and allows for internal 
scrolling within the table
+   * when the number of rows exceeds the visible space.
+   */
+  height?: number;
+}
+
+export enum TableSize {
+  SMALL = 'small',
+  MIDDLE = 'middle',
+}
+
+const defaultRowSelection: React.Key[] = [];
+// This accounts for the tables header and pagination if user gives table 
instance a height. this is a temp solution
+const HEIGHT_OFFSET = 108;
+
+const StyledTable: StyledComponent<any> = styled(AntTable)<any>`
+  ${({ theme, height }) => `
+  .ant-table-body {
+    overflow: scroll;
+    height: ${height ? `${height - HEIGHT_OFFSET}px` : undefined};
+  }
+
+  th.ant-table-cell {
+    font-weight: ${theme.typography.weights.bold};
+    color: ${theme.colors.grayscale.dark1};
+    user-select: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .ant-pagination-item-active {
+    border-color: ${theme.colors.primary.base};
+  }
+  `}
+`;
+
+const defaultLocale = {
+  filterTitle: t('Filter menu'),
+  filterConfirm: t('OK'),
+  filterReset: t('Reset'),
+  filterEmptyText: t('No filters'),
+  filterCheckall: t('Select all items'),
+  filterSearchPlaceholder: t('Search in filters'),
+  emptyText: t('No data'),
+  selectAll: t('Select current page'),
+  selectInvert: t('Invert current page'),
+  selectNone: t('Clear all data'),
+  selectionAll: t('Select all data'),
+  sortTitle: t('Sort'),
+  expand: t('Expand row'),
+  collapse: t('Collapse row'),
+  triggerDesc: t('Click to sort descending'),
+  triggerAsc: t('Click to sort ascending'),
+  cancelSort: t('Click to cancel sorting'),
+};
+
+const selectionMap = {};
+selectionMap[SelectionType.MULTI] = 'checkbox';
+selectionMap[SelectionType.SINGLE] = 'radio';
+selectionMap[SelectionType.DISABLED] = null;
+
+export function Table(props: TableProps) {
+  const {
+    data,
+    columns,
+    selectedRows = defaultRowSelection,
+    handleRowSelection,
+    size,
+    selectionType = SelectionType.DISABLED,
+    sticky = true,
+    loading = false,
+    resizable = false,
+    reorderable = false,
+    defaultPageSize = 15,
+    pageSizeOptions = ['5', '15', '25', '50', '100'],
+    hideData = false,
+    emptyComponent,
+    locale,
+    ...rest
+  } = props;
+
+  const wrapperRef = useRef<HTMLDivElement | null>(null);
+  const [derivedColumns, setDerivedColumns] = useState(columns);
+  const [pageSize, setPageSize] = useState(defaultPageSize);
+  const [mergedLocale, setMergedLocale] = useState({ ...defaultLocale });
+  const [selectedRowKeys, setSelectedRowKeys] =
+    useState<React.Key[]>(selectedRows);
+  const interactiveTableUtils = useRef<InteractiveTableUtils | null>(null);
+
+  const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
+    setSelectedRowKeys(newSelectedRowKeys);
+    handleRowSelection?.(newSelectedRowKeys);
+  };
+
+  const selectionTypeValue = selectionMap[selectionType];
+  const rowSelection = {
+    type: selectionTypeValue,
+    selectedRowKeys,
+    onChange: onSelectChange,
+  };
+
+  const renderEmpty = () =>
+    emptyComponent ?? <div>{mergedLocale.emptyText}</div>;
+
+  const initializeInteractiveTable = () => {
+    if (interactiveTableUtils.current) {
+      interactiveTableUtils.current?.clearListeners();
+    }
+    const table = wrapperRef.current?.getElementsByTagName('table')[0];
+    if (table) {
+      interactiveTableUtils.current = new InteractiveTableUtils(
+        table,
+        derivedColumns,
+        setDerivedColumns,
+      );
+      if (reorderable) {
+        interactiveTableUtils?.current?.initializeDragDropColumns(
+          reorderable,
+          table,
+        );
+      }
+      if (resizable) {
+        interactiveTableUtils?.current?.initializeResizableColumns(
+          resizable,
+          table,
+        );
+      }
+    }
+  };
+
+  // Log use of experimental features
+  useEffect(() => {
+    if (reorderable === true) {
+      // eslint-disable-next-line no-console
+      console.warn(
+        'EXPERIMENTAL FEATURE ENABLED: The "reorderable" prop of Table is 
experimental and NOT recommended for use in production deployments.',
+      );
+    }
+    if (resizable === true) {
+      // eslint-disable-next-line no-console
+      console.warn(
+        'EXPERIMENTAL FEATURE ENABLED: The "resizable" prop of Table is 
experimental and NOT recommended for use in production deployments.',
+      );
+    }
+  }, [reorderable, resizable]);
+
+  useEffect(() => {
+    let updatedLocale;
+    if (locale) {
+      // This spread allows for locale to only contain a subset of locale 
overrides on props
+      updatedLocale = { ...defaultLocale, ...locale };
+    } else {
+      updatedLocale = { ...defaultLocale };
+    }
+    setMergedLocale(updatedLocale);
+  }, [locale]);
+
+  useEffect(() => {
+    initializeInteractiveTable();
+    return () => {
+      interactiveTableUtils?.current?.clearListeners?.();
+    };
+    // eslint-disable-next-line react-hooks/exhaustive-deps
+  }, [wrapperRef, reorderable, resizable]);

Review Comment:
   Can you add the `initializeInteractiveTable` dependency and wrap the 
function with `useCallback`?



##########
superset-frontend/src/components/DesignSystem.stories.mdx:
##########
@@ -0,0 +1,25 @@
+import { Meta, Source } from '@storybook/addon-docs';
+import AtomicDesign from './atomic-design.png';
+
+<Meta title="Design System/Introduction" />
+
+# Superset Design System
+
+A design system is a complete set of standards intended to manage design at 
scale using reusable components and patterns.
+
+You can get an overview of Atmomic Design concepts and link to full book on 
the topic here:
+
+<a href="https://bradfrost.com/blog/post/atomic-web-design/"; target="_blank">
+  Intro to Atomic Design
+</a>
+
+While the Superset Design System will use Atomic Design priciples, we are 
choosing different language to describe the elements.

Review Comment:
   ```suggestion
   While the Superset Design System will use Atomic Design principles, we 
choose a different language to describe the elements.
   ```



##########
superset-frontend/src/components/Table/Table.test.tsx:
##########
@@ -0,0 +1,85 @@
+/**
+ * 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 from 'react';
+import { render, screen } from 'spec/helpers/testing-library';
+import type { ColumnsType } from 'antd/es/table';
+import { Table, TableSize } from './index';
+
+interface BasicData {
+  columnName: string;
+  columnType: string;
+  dataType: string;
+}
+
+const testData: BasicData[] = [
+  {
+    columnName: 'Number',
+    columnType: 'Numerical',
+    dataType: 'number',
+  },
+  {
+    columnName: 'String',
+    columnType: 'Physical',
+    dataType: 'string',
+  },
+  {
+    columnName: 'Date',
+    columnType: 'Virtual',
+    dataType: 'date',
+  },
+];
+
+const testColumns: ColumnsType<BasicData> = [
+  {
+    title: 'Column Name',
+    dataIndex: 'columnName',
+    key: 'columnName',
+  },
+  {
+    title: 'Column Type',
+    dataIndex: 'columnType',
+    key: 'columnType',
+  },
+  {
+    title: 'Data Type',
+    dataIndex: 'dataType',
+    key: 'dataType',
+  },
+];
+
+test('renders with default props', async () => {
+  render(
+    <Table size={TableSize.MIDDLE} columns={testColumns} data={testData} />,
+  );
+  expect(
+    await screen.findByText(testColumns[0].title as string),
+  ).toBeInTheDocument();
+  expect(
+    await screen.findByText(testColumns[1].title as string),
+  ).toBeInTheDocument();
+  expect(
+    await screen.findByText(testColumns[2].title as string),
+  ).toBeInTheDocument();

Review Comment:
   ```suggestion
     await waitFor(() =>
       testColumns.forEach(column =>
         expect(screen.getByText(column.title as string)).toBeInTheDocument(),
       ),
     );
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx:
##########
@@ -0,0 +1,69 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Cell 
Renderers/ActionCell/Overview" />
+
+# ActionCell
+
+An ActionCell is used to display overflow icon that opens a menu allowing the 
user to take actions
+specific to the data in the table row that the cell is a member of.
+
+### [Basic 
example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic)
+
+<Story id="design-system-components-table-cell-renderers-actioncell--basic" />
+
+---
+
+## Usage
+
+The action cell accepts an array of objects that define the label, tooltip, an 
onClick callback functions
+and an optional data payload to be provided back to the onClick handler 
function.

Review Comment:
   ```suggestion
   The action cell accepts an array of objects that define the label, tooltip, 
onClick callback functions,
   and an optional data payload to be provided back to the onClick handler 
function.
   ```



##########
superset-frontend/src/components/Table/Table.stories.tsx:
##########
@@ -0,0 +1,471 @@
+/**
+ * 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 from 'react';
+import { ComponentStory, ComponentMeta } from '@storybook/react';
+import { supersetTheme, ThemeProvider } from '@superset-ui/core';
+import { ColumnsType } from 'antd/es/table';
+import { Table, TableSize, SUPERSET_TABLE_COLUMN } from './index';
+import { numericalSort, alphabeticalSort } from './sorters';
+import ButtonCell from './cell-renderers/ButtonCell';
+import ActionCell from './cell-renderers/ActionCell';
+import { exampleMenuOptions } from './cell-renderers/ActionCell/fixtures';
+import NumericCell, {
+  CurrencyCode,
+  LocaleCode,
+  Style,
+} from './cell-renderers/NumericCell';
+
+export default {
+  title: 'Design System/Components/Table/Examples',
+  component: Table,
+} as ComponentMeta<typeof Table>;
+
+// eslint-disable-next-line no-alert
+const handleClick = (data: object, index: number) =>
+  alert(`I was Clicked: ${JSON.stringify(data)}, index: ${index}`);

Review Comment:
   Can we use Storybook actions for this purpose instead of alerts? You can 
check the MetadataBar component for an example.



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/index.tsx:
##########
@@ -0,0 +1,146 @@
+/**
+ * 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, { useState, useEffect } from 'react';
+import { styled } from '@superset-ui/core';
+import { Dropdown, IconOrientation } from 'src/components/Dropdown';
+import { Menu } from 'src/components/Menu';
+import { MenuProps } from 'antd/lib/menu';
+
+/**
+ * Props interface for Action Cell Renderer
+ */
+export interface ActionCellProps {
+  /**
+   * The Menu option presented to user when menu displays
+   */
+  menuOptions: ActionMenuItem[];
+  /**
+   * Object representing the data rendering the Table row with attribute for 
each column
+   */
+  row: object;
+}
+
+export interface ActionMenuItem {
+  /**
+   * Click handler specific to the menu item
+   * @param menuItem The definition of the menu item that was clicked
+   * @returns ActionMenuItem
+   */
+  onClick: (menuItem: ActionMenuItem) => void;
+  /**
+   * Label user will see displayed in the list of menu options
+   */
+  label: string;
+  /**
+   * Optional tooltip user will see if they hover over the menu option to get 
more context
+   */
+  tooltip?: string;
+  /**
+   * Optional variable that can contain data relevant to the menu item that you
+   * want easy access to in the callback function for the menu
+   */
+  payload?: any;
+  /**
+   * Object representing the data rendering the Table row with attribute for 
each column
+   */
+  row?: object;
+}
+
+/**
+ * Props interface for ActionMenu
+ */
+export interface ActionMenuProps {
+  menuOptions: ActionMenuItem[];
+  setVisible: (visible: boolean) => void;
+}
+
+const SHADOW =
+  'box-shadow: 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px 9px 28px 8px rgba(0, 
0, 0, 0.05)';
+const FILTER = 'drop-shadow(0px 6px 16px rgba(0, 0, 0, 0.08))';
+
+const StyledMenu = styled(Menu)`
+  box-shadow: ${SHADOW} !important;

Review Comment:
   Can we use theme colors for the shadow? You can pick the closest one.



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.overview.mdx:
##########
@@ -0,0 +1,69 @@
+import { Meta, Source, Story, ArgsTable } from '@storybook/addon-docs';
+
+<Meta title="Design System/Components/Table/Cell 
Renderers/ActionCell/Overview" />
+
+# ActionCell
+
+An ActionCell is used to display overflow icon that opens a menu allowing the 
user to take actions
+specific to the data in the table row that the cell is a member of.
+
+### [Basic 
example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic)
+
+<Story id="design-system-components-table-cell-renderers-actioncell--basic" />
+
+---
+
+## Usage
+
+The action cell accepts an array of objects that define the label, tooltip, an 
onClick callback functions
+and an optional data payload to be provided back to the onClick handler 
function.
+
+### [Basic 
example](./?path=/docs/design-system-components-table-cell-renderers-actioncell--basic)
+
+<Story id="design-system-components-table-cell-renderers-actioncell--basic" />
+
+```
+import { ActionMenuItem } from 'src/components/Table/cell-renderers/index';
+
+export const exampleMenuOptions: ActionMenuItem[] = [
+  {
+    label: 'Action 1',
+    tooltip: "This is a tip, don't spend it all in one place",
+    onClick: (item: ActionMenuItem) => {
+      // eslint-disable-next-line no-alert
+      alert(JSON.stringify(item));
+    },
+    payload: {
+      taco: 'spicy chicken',
+    },
+  },
+  {
+    label: 'Action 2',
+    tooltip: 'This is another tip',
+    onClick: (item: ActionMenuItem) => {
+      // eslint-disable-next-line no-alert
+      alert(JSON.stringify(item));
+    },
+    payload: {
+      taco: 'saucy tofu',
+    },
+  },
+];
+
+```
+
+Within context of adding an action cell to cell definitions provided to the 
table using the ActionCell component

Review Comment:
   ```suggestion
   Within the context of adding an action cell to cell definitions provided to 
the table using the ActionCell component
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/ActionCell.test.tsx:
##########
@@ -0,0 +1,49 @@
+/**
+ * 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 from 'react';
+import { render, screen } from 'spec/helpers/testing-library';
+import { configure } from '@testing-library/react';

Review Comment:
   ```suggestion
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ButtonCell/index.tsx:
##########
@@ -0,0 +1,58 @@
+/**
+ * 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 from 'react';
+import Button, { ButtonStyle, ButtonSize } from 'src/components/Button';
+
+type onClickFunction = (row: object, index: number) => void;

Review Comment:
   ```suggestion
   type onClickFunction = (row: object, index: number) => void;
   
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ActionCell/index.tsx:
##########
@@ -0,0 +1,146 @@
+/**
+ * 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, { useState, useEffect } from 'react';
+import { styled } from '@superset-ui/core';
+import { Dropdown, IconOrientation } from 'src/components/Dropdown';
+import { Menu } from 'src/components/Menu';
+import { MenuProps } from 'antd/lib/menu';
+
+/**
+ * Props interface for Action Cell Renderer
+ */
+export interface ActionCellProps {
+  /**
+   * The Menu option presented to user when menu displays
+   */
+  menuOptions: ActionMenuItem[];
+  /**
+   * Object representing the data rendering the Table row with attribute for 
each column
+   */
+  row: object;
+}
+
+export interface ActionMenuItem {
+  /**
+   * Click handler specific to the menu item
+   * @param menuItem The definition of the menu item that was clicked
+   * @returns ActionMenuItem
+   */
+  onClick: (menuItem: ActionMenuItem) => void;
+  /**
+   * Label user will see displayed in the list of menu options
+   */
+  label: string;
+  /**
+   * Optional tooltip user will see if they hover over the menu option to get 
more context
+   */
+  tooltip?: string;
+  /**
+   * Optional variable that can contain data relevant to the menu item that you
+   * want easy access to in the callback function for the menu
+   */
+  payload?: any;
+  /**
+   * Object representing the data rendering the Table row with attribute for 
each column
+   */
+  row?: object;
+}
+
+/**
+ * Props interface for ActionMenu
+ */
+export interface ActionMenuProps {
+  menuOptions: ActionMenuItem[];
+  setVisible: (visible: boolean) => void;
+}
+
+const SHADOW =
+  'box-shadow: 0px 3px 6px -4px rgba(0, 0, 0, 0.12), 0px 9px 28px 8px rgba(0, 
0, 0, 0.05)';
+const FILTER = 'drop-shadow(0px 6px 16px rgba(0, 0, 0, 0.08))';
+
+const StyledMenu = styled(Menu)`
+  box-shadow: ${SHADOW} !important;

Review Comment:
   We always try to avoid `!important`.  Is it possible to use a more specific 
selector?



##########
superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.stories.tsx:
##########
@@ -0,0 +1,63 @@
+/**
+ * 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 from 'react';
+import { ComponentStory, ComponentMeta } from '@storybook/react';
+import { ButtonCell } from './index';
+
+export default {
+  title: 'Design System/Components/Table/Cell Renderers/ButtonCell',
+  component: ButtonCell,
+} as ComponentMeta<typeof ButtonCell>;
+
+// eslint-disable-next-line no-alert
+const clickHandler = () => alert(`I was Clicked`);

Review Comment:
   Same as before. Use Storybook actions instead of alerts.



##########
superset-frontend/src/components/Table/cell-renderers/NumericCell/index.tsx:
##########
@@ -0,0 +1,419 @@
+/**
+ * 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 from 'react';

Review Comment:
   ```suggestion
   import React from 'react';
   import { logging } from '@superset-ui/core';
   ```



##########
superset-frontend/src/components/Table/cell-renderers/ButtonCell/ButtonCell.test.tsx:
##########
@@ -0,0 +1,43 @@
+/**
+ * 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 from 'react';
+import { render, screen } from 'spec/helpers/testing-library';
+import { configure } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+import ButtonCell from './index';
+import { exampleRow } from '../fixtures';
+
+test('renders with default props', async () => {
+  configure({ testIdAttribute: 'data-test' });

Review Comment:
   ```suggestion
   ```



##########
superset-frontend/src/components/Table/cell-renderers/NumericCell/index.tsx:
##########
@@ -0,0 +1,419 @@
+/**
+ * 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 from 'react';
+
+export interface NumericCellProps {
+  /**
+   * The number to display (before optional formatting applied)
+   */
+  value: number;
+  /**
+   * ISO 639-1 language code with optional region or script modifier (e.g. 
en_US).
+   */
+  locale?: LocaleCode;
+  /**
+   * Options for number formatting
+   */
+  options?: NumberOptions;
+}
+
+interface NumberOptions {
+  /**
+   * Style of number to display
+   */
+  style?: Style;
+
+  /**
+   * ISO 4217 currency code
+   */
+  currency?: CurrencyCode;
+
+  /**
+   * Languages in the form of a ISO 639-1 language code with optional region 
or script modifier (e.g. de_AT).
+   */
+  maximumFractionDigits?: number;
+
+  /**
+   * A number from 1 to 21 (default is 21)
+   */
+  maximumSignificantDigits?: number;
+
+  /**
+   * A number from 0 to 20 (default is 3)
+   */
+  minimumFractionDigits?: number;
+
+  /**
+   * A number from 1 to 21 (default is 1)
+   */
+  minimumIntegerDigits?: number;
+
+  /**
+   * A number from 1 to 21 (default is 21)
+   */
+  minimumSignificantDigits?: number;
+}
+
+export enum Style {
+  CURRENCY = 'currency',
+  DECIMAL = 'decimal',
+  PERCENT = 'percent',
+}
+
+export enum CurrencyDisplay {
+  SYMBOL = 'symbol',
+  CODE = 'code',
+  NAME = 'name',
+}
+
+export enum LocaleCode {
+  af = 'af',
+  ak = 'ak',
+  sq = 'sq',
+  am = 'am',
+  ar = 'ar',
+  hy = 'hy',
+  as = 'as',
+  az = 'az',
+  bm = 'bm',
+  bn = 'bn',
+  eu = 'eu',
+  be = 'be',
+  bs = 'bs',
+  br = 'br',
+  bg = 'bg',
+  my = 'my',
+  ca = 'ca',
+  ce = 'ce',
+  zh = 'zh',
+  zh_Hans = 'zh-Hans',
+  zh_Hant = 'zh-Hant',
+  cu = 'cu',
+  kw = 'kw',
+  co = 'co',
+  hr = 'hr',
+  cs = 'cs',
+  da = 'da',
+  nl = 'nl',
+  nl_BE = 'nl-BE',
+  dz = 'dz',
+  en = 'en',
+  en_AU = 'en-AU',
+  en_CA = 'en-CA',
+  en_GB = 'en-GB',
+  en_US = 'en-US',
+  eo = 'eo',
+  et = 'et',
+  ee = 'ee',
+  fo = 'fo',
+  fi = 'fi',
+  fr = 'fr',
+  fr_CA = 'fr-CA',
+  fr_CH = 'fr-CH',
+  ff = 'ff',
+  gl = 'gl',
+  lg = 'lg',
+  ka = 'ka',
+  de = 'de',
+  de_AT = 'de-AT',
+  de_CH = 'de-CH',
+  el = 'el',
+  gu = 'gu',
+  ht = 'ht',
+  ha = 'ha',
+  he = 'he',
+  hi = 'hi',
+  hu = 'hu',
+  is = 'is',
+  ig = 'ig',
+  id = 'id',
+  ia = 'ia',
+  ga = 'ga',
+  it = 'it',
+  ja = 'ja',
+  jv = 'jv',
+  kl = 'kl',
+  kn = 'kn',
+  ks = 'ks',
+  kk = 'kk',
+  km = 'km',
+  ki = 'ki',
+  rw = 'rw',
+  ko = 'ko',
+  ku = 'ku',
+  ky = 'ky',
+  lo = 'lo',
+  la = 'la',
+  lv = 'lv',
+  ln = 'ln',
+  lt = 'lt',
+  lu = 'lu',
+  lb = 'lb',
+  mk = 'mk',
+  mg = 'mg',
+  ms = 'ms',
+  ml = 'ml',
+  mt = 'mt',
+  gv = 'gv',
+  mi = 'mi',
+  mr = 'mr',
+  mn = 'mn',
+  ne = 'ne',
+  nd = 'nd',
+  se = 'se',
+  nb = 'nb',
+  nn = 'nn',
+  ny = 'ny',
+  or = 'or',
+  om = 'om',
+  os = 'os',
+  ps = 'ps',
+  fa = 'fa',
+  fa_AF = 'fa-AF',
+  pl = 'pl',
+  pt = 'pt',
+  pt_BR = 'pt-BR',
+  pt_PT = 'pt-PT',
+  pa = 'pa',
+  qu = 'qu',
+  ro = 'ro',
+  ro_MD = 'ro-MD',
+  rm = 'rm',
+  rn = 'rn',
+  ru = 'ru',
+  sm = 'sm',
+  sg = 'sg',
+  sa = 'sa',
+  gd = 'gd',
+  sr = 'sr',
+  sn = 'sn',
+  ii = 'ii',
+  sd = 'sd',
+  si = 'si',
+  sk = 'sk',
+  sl = 'sl',
+  so = 'so',
+  st = 'st',
+  es = 'es',
+  es_ES = 'es-ES',
+  es_MX = 'es-MX',
+  su = 'su',
+  sw = 'sw',
+  sw_CD = 'sw-CD',
+  sv = 'sv',
+  tg = 'tg',
+  ta = 'ta',
+  tt = 'tt',
+  te = 'te',
+  th = 'th',
+  bo = 'bo',
+  ti = 'ti',
+  to = 'to',
+  tr = 'tr',
+  tk = 'tk',
+  uk = 'uk',
+  ur = 'ur',
+  ug = 'ug',
+  uz = 'uz',
+  vi = 'vi',
+  vo = 'vo',
+  cy = 'cy',
+  fy = 'fy',
+  wo = 'wo',
+  xh = 'xh',
+  yi = 'yi',
+  yo = 'yo',
+  zu = 'zu',
+}
+
+export enum CurrencyCode {
+  AED = 'AED',
+  AFN = 'AFN',
+  ALL = 'ALL',
+  AMD = 'AMD',
+  ANG = 'ANG',
+  AOA = 'AOA',
+  ARS = 'ARS',
+  AUD = 'AUD',
+  AWG = 'AWG',
+  AZN = 'AZN',
+  BAM = 'BAM',
+  BBD = 'BBD',
+  BDT = 'BDT',
+  BGN = 'BGN',
+  BHD = 'BHD',
+  BIF = 'BIF',
+  BMD = 'BMD',
+  BND = 'BND',
+  BOB = 'BOB',
+  BRL = 'BRL',
+  BSD = 'BSD',
+  BTN = 'BTN',
+  BWP = 'BWP',
+  BYN = 'BYN',
+  BZD = 'BZD',
+  CAD = 'CAD',
+  CDF = 'CDF',
+  CHF = 'CHF',
+  CLP = 'CLP',
+  CNY = 'CNY',
+  COP = 'COP',
+  CRC = 'CRC',
+  CUC = 'CUC',
+  CUP = 'CUP',
+  CVE = 'CVE',
+  CZK = 'CZK',
+  DJF = 'DJF',
+  DKK = 'DKK',
+  DOP = 'DOP',
+  DZD = 'DZD',
+  EGP = 'EGP',
+  ERN = 'ERN',
+  ETB = 'ETB',
+  EUR = 'EUR',
+  FJD = 'FJD',
+  FKP = 'FKP',
+  GBP = 'GBP',
+  GEL = 'GEL',
+  GHS = 'GHS',
+  GIP = 'GIP',
+  GMD = 'GMD',
+  GNF = 'GNF',
+  GTQ = 'GTQ',
+  GYD = 'GYD',
+  HKD = 'HKD',
+  HNL = 'HNL',
+  HRK = 'HRK',
+  HTG = 'HTG',
+  HUF = 'HUF',
+  IDR = 'IDR',
+  ILS = 'ILS',
+  INR = 'INR',
+  IQD = 'IQD',
+  IRR = 'IRR',
+  ISK = 'ISK',
+  JMD = 'JMD',
+  JOD = 'JOD',
+  JPY = 'JPY',
+  KES = 'KES',
+  KGS = 'KGS',
+  KHR = 'KHR',
+  KMF = 'KMF',
+  KPW = 'KPW',
+  KRW = 'KRW',
+  KWD = 'KWD',
+  KYD = 'KYD',
+  KZT = 'KZT',
+  LAK = 'LAK',
+  LBP = 'LBP',
+  LKR = 'LKR',
+  LRD = 'LRD',
+  LSL = 'LSL',
+  LYD = 'LYD',
+  MAD = 'MAD',
+  MDL = 'MDL',
+  MGA = 'MGA',
+  MKD = 'MKD',
+  MMK = 'MMK',
+  MNT = 'MNT',
+  MOP = 'MOP',
+  MRU = 'MRU',
+  MUR = 'MUR',
+  MVR = 'MVR',
+  MWK = 'MWK',
+  MXN = 'MXN',
+  MYR = 'MYR',
+  MZN = 'MZN',
+  NAD = 'NAD',
+  NGN = 'NGN',
+  NIO = 'NIO',
+  NOK = 'NOK',
+  NPR = 'NPR',
+  NZD = 'NZD',
+  OMR = 'OMR',
+  PAB = 'PAB',
+  PEN = 'PEN',
+  PGK = 'PGK',
+  PHP = 'PHP',
+  PKR = 'PKR',
+  PLN = 'PLN',
+  PYG = 'PYG',
+  QAR = 'QAR',
+  RON = 'RON',
+  RSD = 'RSD',
+  RUB = 'RUB',
+  RWF = 'RWF',
+  SAR = 'SAR',
+  SBD = 'SBD',
+  SCR = 'SCR',
+  SDG = 'SDG',
+  SEK = 'SEK',
+  SGD = 'SGD',
+  SHP = 'SHP',
+  SLL = 'SLL',
+  SOS = 'SOS',
+  SRD = 'SRD',
+  SSP = 'SSP',
+  STN = 'STN',
+  SVC = 'SVC',
+  SYP = 'SYP',
+  SZL = 'SZL',
+  THB = 'THB',
+  TJS = 'TJS',
+  TMT = 'TMT',
+  TND = 'TND',
+  TOP = 'TOP',
+  TRY = 'TRY',
+  TTD = 'TTD',
+  TWD = 'TWD',
+  TZS = 'TZS',
+  UAH = 'UAH',
+  UGX = 'UGX',
+  USD = 'USD',
+  UYU = 'UYU',
+  UZS = 'UZS',
+  VES = 'VES',
+  VND = 'VND',
+  VUV = 'VUV',
+  WST = 'WST',
+  XAF = 'XAF',
+  XCD = 'XCD',
+  XOF = 'XOF',
+  XPF = 'XPF',
+  YER = 'YER',
+  ZAR = 'ZAR',
+  ZMW = 'ZMW',
+  ZWL = 'ZWL',
+}
+
+export function NumericCell(props: NumericCellProps) {
+  const { value, locale = LocaleCode.en_US, options } = props;
+  let displayValue = value?.toString() ?? value;
+  try {
+    displayValue = value?.toLocaleString?.(locale, options);
+  } catch (e) {
+    // eslint-disable-next-line no-console
+    console.error(e);

Review Comment:
   ```suggestion
       logging.error(e);
   ```



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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, { useState, useEffect, useRef, ReactElement } from 'react';
+import { Table as AntTable, ConfigProvider } from 'antd';
+import type { ColumnsType, TableProps as AntTableProps } from 'antd/es/table';
+import { t, useTheme } from '@superset-ui/core';
+import Loading from 'src/components/Loading';
+import styled, { StyledComponent } from '@emotion/styled';
+import InteractiveTableUtils from './utils/InteractiveTableUtils';
+
+export const SUPERSET_TABLE_COLUMN = 'superset/table-column';
+export interface TableDataType {
+  key: React.Key;
+}
+
+export enum SelectionType {
+  'DISABLED' = 'disabled',
+  'SINGLE' = 'single',
+  'MULTI' = 'multi',
+}
+
+export interface Locale {
+  /**
+   * Text contained within the Table UI.
+   */
+  filterTitle: string;
+  filterConfirm: string;
+  filterReset: string;
+  filterEmptyText: string;
+  filterCheckall: string;
+  filterSearchPlaceholder: string;
+  emptyText: string;
+  selectAll: string;
+  selectInvert: string;
+  selectNone: string;
+  selectionAll: string;
+  sortTitle: string;
+  expand: string;
+  collapse: string;
+  triggerDesc: string;
+  triggerAsc: string;
+  cancelSort: string;
+}
+
+export interface TableProps extends AntTableProps<TableProps> {
+  /**
+   * Data that will populate the each row and map to the column key.
+   */
+  data: object[];
+  /**
+   * Table column definitions.
+   */
+  columns: ColumnsType<any>;
+  /**
+   * Array of row keys to represent list of selected rows.
+   */
+  selectedRows?: React.Key[];
+  /**
+   * Callback function invoked when a row is selected by user.
+   */
+  handleRowSelection?: Function;
+  /**
+   * Controls the size of the table.
+   */
+  size: TableSize;
+  /**
+   * Adjusts the padding around elements for different amounts of spacing 
between elements.
+   */
+  selectionType?: SelectionType;
+  /*
+   * Places table in visual loading state.  Use while waiting to retrieve data 
or perform an async operation that will update the table.
+   */
+  loading?: boolean;
+  /**
+   * Uses a sticky header which always displays when vertically scrolling the 
table.  Default: true
+   */
+  sticky?: boolean;
+  /**
+   * Controls if columns are resizable by user.
+   */
+  resizable?: boolean;
+  /**
+   * EXPERIMENTAL: Controls if columns are re-orderable by user drag drop.
+   */
+  reorderable?: boolean;
+  /**
+   * Default number of rows table will display per page of data.
+   */
+  defaultPageSize?: number;
+  /**
+   * Array of numeric options for the number of rows table will display per 
page of data.
+   * The user can select from these options in the page size drop down menu.
+   */
+  pageSizeOptions?: string[];
+  /**
+   * Set table to display no data even if data has been provided
+   */
+  hideData?: boolean;
+  /**
+   * emptyComponent
+   */
+  emptyComponent?: ReactElement;
+  /**
+   * Enables setting the text displayed in various components and tooltips 
within the Table UI.
+   */
+  locale?: Locale;
+  /**
+   * Restricts the visible height of the table and allows for internal 
scrolling within the table
+   * when the number of rows exceeds the visible space.
+   */
+  height?: number;
+}
+
+export enum TableSize {
+  SMALL = 'small',
+  MIDDLE = 'middle',
+}
+
+const defaultRowSelection: React.Key[] = [];
+// This accounts for the tables header and pagination if user gives table 
instance a height. this is a temp solution
+const HEIGHT_OFFSET = 108;
+
+const StyledTable: StyledComponent<any> = styled(AntTable)<any>`
+  ${({ theme, height }) => `
+  .ant-table-body {
+    overflow: scroll;
+    height: ${height ? `${height - HEIGHT_OFFSET}px` : undefined};
+  }
+
+  th.ant-table-cell {
+    font-weight: ${theme.typography.weights.bold};
+    color: ${theme.colors.grayscale.dark1};
+    user-select: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .ant-pagination-item-active {
+    border-color: ${theme.colors.primary.base};
+  }
+  `}
+`;
+
+const defaultLocale = {
+  filterTitle: t('Filter menu'),
+  filterConfirm: t('OK'),
+  filterReset: t('Reset'),
+  filterEmptyText: t('No filters'),
+  filterCheckall: t('Select all items'),
+  filterSearchPlaceholder: t('Search in filters'),
+  emptyText: t('No data'),
+  selectAll: t('Select current page'),
+  selectInvert: t('Invert current page'),
+  selectNone: t('Clear all data'),
+  selectionAll: t('Select all data'),
+  sortTitle: t('Sort'),
+  expand: t('Expand row'),
+  collapse: t('Collapse row'),
+  triggerDesc: t('Click to sort descending'),
+  triggerAsc: t('Click to sort ascending'),
+  cancelSort: t('Click to cancel sorting'),
+};
+
+const selectionMap = {};
+selectionMap[SelectionType.MULTI] = 'checkbox';
+selectionMap[SelectionType.SINGLE] = 'radio';
+selectionMap[SelectionType.DISABLED] = null;
+
+export function Table(props: TableProps) {
+  const {
+    data,
+    columns,
+    selectedRows = defaultRowSelection,
+    handleRowSelection,
+    size,
+    selectionType = SelectionType.DISABLED,
+    sticky = true,
+    loading = false,
+    resizable = false,
+    reorderable = false,
+    defaultPageSize = 15,
+    pageSizeOptions = ['5', '15', '25', '50', '100'],
+    hideData = false,
+    emptyComponent,
+    locale,
+    ...rest
+  } = props;
+
+  const wrapperRef = useRef<HTMLDivElement | null>(null);
+  const [derivedColumns, setDerivedColumns] = useState(columns);
+  const [pageSize, setPageSize] = useState(defaultPageSize);
+  const [mergedLocale, setMergedLocale] = useState({ ...defaultLocale });
+  const [selectedRowKeys, setSelectedRowKeys] =
+    useState<React.Key[]>(selectedRows);
+  const interactiveTableUtils = useRef<InteractiveTableUtils | null>(null);
+
+  const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
+    setSelectedRowKeys(newSelectedRowKeys);
+    handleRowSelection?.(newSelectedRowKeys);
+  };
+
+  const selectionTypeValue = selectionMap[selectionType];
+  const rowSelection = {
+    type: selectionTypeValue,
+    selectedRowKeys,
+    onChange: onSelectChange,
+  };
+
+  const renderEmpty = () =>
+    emptyComponent ?? <div>{mergedLocale.emptyText}</div>;
+
+  const initializeInteractiveTable = () => {
+    if (interactiveTableUtils.current) {
+      interactiveTableUtils.current?.clearListeners();
+    }
+    const table = wrapperRef.current?.getElementsByTagName('table')[0];
+    if (table) {
+      interactiveTableUtils.current = new InteractiveTableUtils(
+        table,
+        derivedColumns,
+        setDerivedColumns,
+      );
+      if (reorderable) {
+        interactiveTableUtils?.current?.initializeDragDropColumns(
+          reorderable,
+          table,
+        );
+      }
+      if (resizable) {
+        interactiveTableUtils?.current?.initializeResizableColumns(
+          resizable,
+          table,
+        );
+      }
+    }
+  };
+
+  // Log use of experimental features
+  useEffect(() => {
+    if (reorderable === true) {
+      // eslint-disable-next-line no-console
+      console.warn(
+        'EXPERIMENTAL FEATURE ENABLED: The "reorderable" prop of Table is 
experimental and NOT recommended for use in production deployments.',
+      );
+    }
+    if (resizable === true) {
+      // eslint-disable-next-line no-console
+      console.warn(

Review Comment:
   ```suggestion
         logging.warn(
   ```



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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, { useState, useEffect, useRef, ReactElement } from 'react';
+import { Table as AntTable, ConfigProvider } from 'antd';
+import type { ColumnsType, TableProps as AntTableProps } from 'antd/es/table';
+import { t, useTheme } from '@superset-ui/core';
+import Loading from 'src/components/Loading';
+import styled, { StyledComponent } from '@emotion/styled';
+import InteractiveTableUtils from './utils/InteractiveTableUtils';
+
+export const SUPERSET_TABLE_COLUMN = 'superset/table-column';
+export interface TableDataType {
+  key: React.Key;
+}
+
+export enum SelectionType {
+  'DISABLED' = 'disabled',
+  'SINGLE' = 'single',
+  'MULTI' = 'multi',
+}
+
+export interface Locale {
+  /**
+   * Text contained within the Table UI.
+   */
+  filterTitle: string;
+  filterConfirm: string;
+  filterReset: string;
+  filterEmptyText: string;
+  filterCheckall: string;
+  filterSearchPlaceholder: string;
+  emptyText: string;
+  selectAll: string;
+  selectInvert: string;
+  selectNone: string;
+  selectionAll: string;
+  sortTitle: string;
+  expand: string;
+  collapse: string;
+  triggerDesc: string;
+  triggerAsc: string;
+  cancelSort: string;
+}
+
+export interface TableProps extends AntTableProps<TableProps> {
+  /**
+   * Data that will populate the each row and map to the column key.
+   */
+  data: object[];
+  /**
+   * Table column definitions.
+   */
+  columns: ColumnsType<any>;
+  /**
+   * Array of row keys to represent list of selected rows.
+   */
+  selectedRows?: React.Key[];
+  /**
+   * Callback function invoked when a row is selected by user.
+   */
+  handleRowSelection?: Function;
+  /**
+   * Controls the size of the table.
+   */
+  size: TableSize;
+  /**
+   * Adjusts the padding around elements for different amounts of spacing 
between elements.
+   */
+  selectionType?: SelectionType;
+  /*
+   * Places table in visual loading state.  Use while waiting to retrieve data 
or perform an async operation that will update the table.
+   */
+  loading?: boolean;
+  /**
+   * Uses a sticky header which always displays when vertically scrolling the 
table.  Default: true
+   */
+  sticky?: boolean;
+  /**
+   * Controls if columns are resizable by user.
+   */
+  resizable?: boolean;
+  /**
+   * EXPERIMENTAL: Controls if columns are re-orderable by user drag drop.
+   */
+  reorderable?: boolean;
+  /**
+   * Default number of rows table will display per page of data.
+   */
+  defaultPageSize?: number;
+  /**
+   * Array of numeric options for the number of rows table will display per 
page of data.
+   * The user can select from these options in the page size drop down menu.
+   */
+  pageSizeOptions?: string[];
+  /**
+   * Set table to display no data even if data has been provided
+   */
+  hideData?: boolean;
+  /**
+   * emptyComponent
+   */
+  emptyComponent?: ReactElement;
+  /**
+   * Enables setting the text displayed in various components and tooltips 
within the Table UI.
+   */
+  locale?: Locale;
+  /**
+   * Restricts the visible height of the table and allows for internal 
scrolling within the table
+   * when the number of rows exceeds the visible space.
+   */
+  height?: number;
+}
+
+export enum TableSize {
+  SMALL = 'small',
+  MIDDLE = 'middle',
+}
+
+const defaultRowSelection: React.Key[] = [];
+// This accounts for the tables header and pagination if user gives table 
instance a height. this is a temp solution
+const HEIGHT_OFFSET = 108;
+
+const StyledTable: StyledComponent<any> = styled(AntTable)<any>`
+  ${({ theme, height }) => `
+  .ant-table-body {
+    overflow: scroll;
+    height: ${height ? `${height - HEIGHT_OFFSET}px` : undefined};
+  }
+
+  th.ant-table-cell {
+    font-weight: ${theme.typography.weights.bold};
+    color: ${theme.colors.grayscale.dark1};
+    user-select: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .ant-pagination-item-active {
+    border-color: ${theme.colors.primary.base};
+  }
+  `}
+`;
+
+const defaultLocale = {
+  filterTitle: t('Filter menu'),
+  filterConfirm: t('OK'),
+  filterReset: t('Reset'),
+  filterEmptyText: t('No filters'),
+  filterCheckall: t('Select all items'),
+  filterSearchPlaceholder: t('Search in filters'),
+  emptyText: t('No data'),
+  selectAll: t('Select current page'),
+  selectInvert: t('Invert current page'),
+  selectNone: t('Clear all data'),
+  selectionAll: t('Select all data'),
+  sortTitle: t('Sort'),
+  expand: t('Expand row'),
+  collapse: t('Collapse row'),
+  triggerDesc: t('Click to sort descending'),
+  triggerAsc: t('Click to sort ascending'),
+  cancelSort: t('Click to cancel sorting'),
+};
+
+const selectionMap = {};
+selectionMap[SelectionType.MULTI] = 'checkbox';
+selectionMap[SelectionType.SINGLE] = 'radio';
+selectionMap[SelectionType.DISABLED] = null;
+
+export function Table(props: TableProps) {
+  const {
+    data,
+    columns,
+    selectedRows = defaultRowSelection,
+    handleRowSelection,
+    size,
+    selectionType = SelectionType.DISABLED,
+    sticky = true,
+    loading = false,
+    resizable = false,
+    reorderable = false,
+    defaultPageSize = 15,
+    pageSizeOptions = ['5', '15', '25', '50', '100'],
+    hideData = false,
+    emptyComponent,
+    locale,
+    ...rest
+  } = props;
+
+  const wrapperRef = useRef<HTMLDivElement | null>(null);
+  const [derivedColumns, setDerivedColumns] = useState(columns);
+  const [pageSize, setPageSize] = useState(defaultPageSize);
+  const [mergedLocale, setMergedLocale] = useState({ ...defaultLocale });
+  const [selectedRowKeys, setSelectedRowKeys] =
+    useState<React.Key[]>(selectedRows);
+  const interactiveTableUtils = useRef<InteractiveTableUtils | null>(null);
+
+  const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
+    setSelectedRowKeys(newSelectedRowKeys);
+    handleRowSelection?.(newSelectedRowKeys);
+  };
+
+  const selectionTypeValue = selectionMap[selectionType];
+  const rowSelection = {
+    type: selectionTypeValue,
+    selectedRowKeys,
+    onChange: onSelectChange,
+  };
+
+  const renderEmpty = () =>
+    emptyComponent ?? <div>{mergedLocale.emptyText}</div>;
+
+  const initializeInteractiveTable = () => {
+    if (interactiveTableUtils.current) {
+      interactiveTableUtils.current?.clearListeners();
+    }
+    const table = wrapperRef.current?.getElementsByTagName('table')[0];
+    if (table) {
+      interactiveTableUtils.current = new InteractiveTableUtils(
+        table,
+        derivedColumns,
+        setDerivedColumns,
+      );
+      if (reorderable) {
+        interactiveTableUtils?.current?.initializeDragDropColumns(
+          reorderable,
+          table,
+        );
+      }
+      if (resizable) {
+        interactiveTableUtils?.current?.initializeResizableColumns(
+          resizable,
+          table,
+        );
+      }
+    }
+  };
+
+  // Log use of experimental features
+  useEffect(() => {
+    if (reorderable === true) {
+      // eslint-disable-next-line no-console
+      console.warn(

Review Comment:
   ```suggestion
         logging.warn(
   ```



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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, { useState, useEffect, useRef, ReactElement } from 'react';
+import { Table as AntTable, ConfigProvider } from 'antd';
+import type { ColumnsType, TableProps as AntTableProps } from 'antd/es/table';
+import { t, useTheme } from '@superset-ui/core';

Review Comment:
   ```suggestion
   import { t, useTheme, logging } from '@superset-ui/core';
   ```



##########
superset-frontend/src/components/Loading/index.tsx:
##########
@@ -20,6 +20,8 @@
 import React from 'react';
 import { styled } from '@superset-ui/core';
 import cls from 'classnames';
+// @ts-ignore

Review Comment:
   You can follow the same pattern as 
https://github.com/apache/superset/blob/cd1b379bdf323f78c2e7d574525a55898c920942/superset-frontend/plugins/plugin-chart-table/types/external.d.ts#L20
   
   If you search for `declare module` in the codebase you'll see many examples.



##########
superset-frontend/src/components/Table/index.tsx:
##########
@@ -0,0 +1,320 @@
+/**
+ * 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, { useState, useEffect, useRef, ReactElement } from 'react';
+import { Table as AntTable, ConfigProvider } from 'antd';
+import type { ColumnsType, TableProps as AntTableProps } from 'antd/es/table';
+import { t, useTheme } from '@superset-ui/core';
+import Loading from 'src/components/Loading';
+import styled, { StyledComponent } from '@emotion/styled';
+import InteractiveTableUtils from './utils/InteractiveTableUtils';
+
+export const SUPERSET_TABLE_COLUMN = 'superset/table-column';
+export interface TableDataType {
+  key: React.Key;
+}
+
+export enum SelectionType {
+  'DISABLED' = 'disabled',
+  'SINGLE' = 'single',
+  'MULTI' = 'multi',
+}
+
+export interface Locale {
+  /**
+   * Text contained within the Table UI.
+   */
+  filterTitle: string;
+  filterConfirm: string;
+  filterReset: string;
+  filterEmptyText: string;
+  filterCheckall: string;
+  filterSearchPlaceholder: string;
+  emptyText: string;
+  selectAll: string;
+  selectInvert: string;
+  selectNone: string;
+  selectionAll: string;
+  sortTitle: string;
+  expand: string;
+  collapse: string;
+  triggerDesc: string;
+  triggerAsc: string;
+  cancelSort: string;
+}
+
+export interface TableProps extends AntTableProps<TableProps> {
+  /**
+   * Data that will populate the each row and map to the column key.
+   */
+  data: object[];
+  /**
+   * Table column definitions.
+   */
+  columns: ColumnsType<any>;
+  /**
+   * Array of row keys to represent list of selected rows.
+   */
+  selectedRows?: React.Key[];
+  /**
+   * Callback function invoked when a row is selected by user.
+   */
+  handleRowSelection?: Function;
+  /**
+   * Controls the size of the table.
+   */
+  size: TableSize;
+  /**
+   * Adjusts the padding around elements for different amounts of spacing 
between elements.
+   */
+  selectionType?: SelectionType;
+  /*
+   * Places table in visual loading state.  Use while waiting to retrieve data 
or perform an async operation that will update the table.
+   */
+  loading?: boolean;
+  /**
+   * Uses a sticky header which always displays when vertically scrolling the 
table.  Default: true
+   */
+  sticky?: boolean;
+  /**
+   * Controls if columns are resizable by user.
+   */
+  resizable?: boolean;
+  /**
+   * EXPERIMENTAL: Controls if columns are re-orderable by user drag drop.
+   */
+  reorderable?: boolean;
+  /**
+   * Default number of rows table will display per page of data.
+   */
+  defaultPageSize?: number;
+  /**
+   * Array of numeric options for the number of rows table will display per 
page of data.
+   * The user can select from these options in the page size drop down menu.
+   */
+  pageSizeOptions?: string[];
+  /**
+   * Set table to display no data even if data has been provided
+   */
+  hideData?: boolean;
+  /**
+   * emptyComponent
+   */
+  emptyComponent?: ReactElement;
+  /**
+   * Enables setting the text displayed in various components and tooltips 
within the Table UI.
+   */
+  locale?: Locale;
+  /**
+   * Restricts the visible height of the table and allows for internal 
scrolling within the table
+   * when the number of rows exceeds the visible space.
+   */
+  height?: number;
+}
+
+export enum TableSize {
+  SMALL = 'small',
+  MIDDLE = 'middle',
+}
+
+const defaultRowSelection: React.Key[] = [];
+// This accounts for the tables header and pagination if user gives table 
instance a height. this is a temp solution
+const HEIGHT_OFFSET = 108;
+
+const StyledTable: StyledComponent<any> = styled(AntTable)<any>`
+  ${({ theme, height }) => `
+  .ant-table-body {
+    overflow: scroll;
+    height: ${height ? `${height - HEIGHT_OFFSET}px` : undefined};
+  }
+
+  th.ant-table-cell {
+    font-weight: ${theme.typography.weights.bold};
+    color: ${theme.colors.grayscale.dark1};
+    user-select: none;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  .ant-pagination-item-active {
+    border-color: ${theme.colors.primary.base};
+  }
+  `}

Review Comment:
   ```suggestion
     ${({ theme, height }) => `
       .ant-table-body {
         overflow: scroll;
         height: ${height ? `${height - HEIGHT_OFFSET}px` : undefined};
       }
   
       th.ant-table-cell {
         font-weight: ${theme.typography.weights.bold};
         color: ${theme.colors.grayscale.dark1};
         user-select: none;
         white-space: nowrap;
         overflow: hidden;
         text-overflow: ellipsis;
       }
   
       .ant-pagination-item-active {
         border-color: ${theme.colors.primary.base};
       }
     `}
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org
For additional commands, e-mail: notifications-h...@superset.apache.org

Reply via email to