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

erikrit 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 74423e5  deprecate tslint and configure eslint for typescript (#9172)
74423e5 is described below

commit 74423e5d19e78c3195547de94df78693fdce3061
Author: ʈᵃᵢ <tdupree...@gmail.com>
AuthorDate: Thu Feb 20 09:54:33 2020 -0800

    deprecate tslint and configure eslint for typescript (#9172)
---
 superset-frontend/.eslintignore                    |   1 +
 superset-frontend/.eslintrc                        |  89 -------
 superset-frontend/.eslintrc.js                     | 167 ++++++++++++
 superset-frontend/package-lock.json                | 285 +++++++++++++--------
 superset-frontend/package.json                     |  13 +-
 .../spec/javascripts/utils/safeStringify_spec.ts   |   8 +-
 superset-frontend/src/SqlLab/components/Link.tsx   |   2 +-
 superset-frontend/src/SqlLab/utils/sqlKeywords.ts  |   2 +-
 .../src/components/ConfirmStatusChange.tsx         |  17 +-
 .../src/components/ListView/ListView.tsx           | 146 ++++++-----
 .../src/components/ListView/TableCollection.tsx    |  28 +-
 superset-frontend/src/components/ListView/utils.ts |   2 +-
 .../src/dashboard/stylesheets/popover-menu.less    |   3 +-
 superset-frontend/src/utils/safeStringify.ts       |   4 +-
 .../src/views/chartList/ChartList.tsx              | 181 +++++++------
 .../src/views/dashboardList/DashboardList.tsx      | 203 +++++++++------
 superset-frontend/tsconfig.json                    |  26 +-
 superset-frontend/tslint.json                      |  14 -
 18 files changed, 707 insertions(+), 484 deletions(-)

diff --git a/superset-frontend/.eslintignore b/superset-frontend/.eslintignore
index a92bf58..25b08e0 100644
--- a/superset-frontend/.eslintignore
+++ b/superset-frontend/.eslintignore
@@ -26,3 +26,4 @@ vendor/*
 docs/*
 src/dashboard/deprecated/*
 **/node_modules
+*.d.ts
diff --git a/superset-frontend/.eslintrc b/superset-frontend/.eslintrc
deleted file mode 100644
index 34cbfe9..0000000
--- a/superset-frontend/.eslintrc
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * 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.
- */
-{
-  "extends": ["airbnb", "prettier"],
-  "parser": "babel-eslint",
-  "parserOptions": {
-    "ecmaFeatures": {
-      "experimentalObjectRestSpread": true
-    }
-  },
-  "env": {
-    "browser": true
-  },
-  "plugins": ["prettier", "react"],
-  "rules": {
-    "camelcase": [
-      "error",
-      {
-        "allow": ["^UNSAFE_"],
-        "properties": "never"
-      }
-    ],
-    "class-methods-use-this": 0,
-    "func-names": 0,
-    "guard-for-in": 0,
-    "import/extensions": [
-      "error",
-      {
-        ".js": "always",
-        ".jsx": "always",
-        ".ts": "always",
-        ".tsx": "always",
-        ".json": "always"
-      }
-    ],
-    "import/no-named-as-default": 0,
-    "import/prefer-default-export": 0,
-    "indent": 0,
-    "jsx-a11y/anchor-has-content": 0,
-    "jsx-a11y/href-no-hash": 0,
-    "jsx-a11y/no-static-element-interactions": 0,
-    "new-cap": 0,
-    "no-bitwise": 0,
-    "no-confusing-arrow": 0,
-    "no-continue": 0,
-    "no-mixed-operators": 0,
-    "no-multi-assign": 0,
-    "no-multi-spaces": 0,
-    "no-plusplus": 0,
-    "no-prototype-builtins": 0,
-    "no-restricted-properties": 0,
-    "no-restricted-syntax": 0,
-    "padded-blocks": 0,
-    "prefer-arrow-callback": 0,
-    "prefer-template": 0,
-    "react/forbid-prop-types": 0,
-    "react/jsx-no-bind": 0,
-    "react/no-array-index-key": 0,
-    "react/no-string-refs": 0,
-    "react/no-unescaped-entities": 0,
-    "react/no-unused-prop-types": 0,
-    "react/require-default-props": 0,
-    "react/jsx-fragments": 1,
-    "react/prop-types": 0,
-    "prettier/prettier": "error"
-  },
-  "settings": {
-    "import/resolver": "webpack",
-    "react": {
-      "version": "detect"
-    }
-  }
-}
diff --git a/superset-frontend/.eslintrc.js b/superset-frontend/.eslintrc.js
new file mode 100644
index 0000000..f8ec002
--- /dev/null
+++ b/superset-frontend/.eslintrc.js
@@ -0,0 +1,167 @@
+/**
+ * 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.
+ */
+module.exports = {
+  extends: ['airbnb', 'prettier'],
+  parser: 'babel-eslint',
+  parserOptions: {
+    ecmaFeatures: {
+      experimentalObjectRestSpread: true,
+    },
+  },
+  env: {
+    browser: true,
+  },
+  plugins: ['prettier', 'react'],
+  overrides: [
+    {
+      files: ['*.ts', '*.tsx'],
+      parser: '@typescript-eslint/parser',
+      extends: [
+        'airbnb',
+        'plugin:@typescript-eslint/recommended',
+        'prettier',
+        'prettier/@typescript-eslint',
+      ],
+      plugins: ['@typescript-eslint', 'prettier', 'react'],
+      rules: {
+        '@typescript-eslint/ban-ts-ignore': 0,
+        '@typescript-eslint/camelcase': [
+          'error',
+          {
+            allow: ['^UNSAFE_'],
+            properties: 'never',
+          },
+        ],
+        '@typescript-eslint/no-explicit-any': 0,
+        '@typescript-eslint/explicit-function-return-type': 0,
+        camelcase: 0,
+        'class-methods-use-this': 0,
+        'func-names': 0,
+        'guard-for-in': 0,
+        'import/extensions': [
+          'error',
+          {
+            '.ts': 'always',
+            '.tsx': 'always',
+            '.json': 'always',
+          },
+        ],
+        'import/no-named-as-default': 0,
+        'import/no-named-as-default-member': 0,
+        'import/prefer-default-export': 0,
+        indent: 0,
+        'jsx-a11y/anchor-has-content': 0,
+        'jsx-a11y/href-no-hash': 0,
+        'jsx-a11y/no-static-element-interactions': 0,
+        'new-cap': 0,
+        'no-bitwise': 0,
+        'no-confusing-arrow': 0,
+        'no-continue': 0,
+        'no-mixed-operators': 0,
+        'no-multi-assign': 0,
+        'no-multi-spaces': 0,
+        'no-plusplus': 0,
+        'no-prototype-builtins': 0,
+        'no-restricted-properties': 0,
+        'no-restricted-syntax': 0,
+        'no-unused-vars': 0,
+        'padded-blocks': 0,
+        'prefer-arrow-callback': 0,
+        'prefer-template': 0,
+        'react/forbid-prop-types': 0,
+        'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
+        'react/jsx-no-bind': 0,
+        'react/no-array-index-key': 0,
+        'react/no-string-refs': 0,
+        'react/no-unescaped-entities': 0,
+        'react/no-unused-prop-types': 0,
+        'react/require-default-props': 0,
+        'react/jsx-fragments': 1,
+        'react/prop-types': 0,
+        'prettier/prettier': 'error',
+      },
+      settings: {
+        'import/resolver': 'webpack',
+        react: {
+          version: 'detect',
+        },
+      },
+    },
+  ],
+  rules: {
+    camelcase: [
+      'error',
+      {
+        allow: ['^UNSAFE_'],
+        properties: 'never',
+      },
+    ],
+    'class-methods-use-this': 0,
+    'func-names': 0,
+    'guard-for-in': 0,
+    'import/extensions': [
+      'error',
+      {
+        '.js': 'always',
+        '.jsx': 'always',
+        '.ts': 'always',
+        '.tsx': 'always',
+        '.json': 'always',
+      },
+    ],
+    'import/no-named-as-default': 0,
+    'import/prefer-default-export': 0,
+    indent: 0,
+    'jsx-a11y/anchor-has-content': 0,
+    'jsx-a11y/href-no-hash': 0,
+    'jsx-a11y/no-static-element-interactions': 0,
+    'new-cap': 0,
+    'no-bitwise': 0,
+    'no-confusing-arrow': 0,
+    'no-continue': 0,
+    'no-mixed-operators': 0,
+    'no-multi-assign': 0,
+    'no-multi-spaces': 0,
+    'no-plusplus': 0,
+    'no-prototype-builtins': 0,
+    'no-restricted-properties': 0,
+    'no-restricted-syntax': 0,
+    'no-unused-vars': 0,
+    'padded-blocks': 0,
+    'prefer-arrow-callback': 0,
+    'prefer-template': 0,
+    'react/forbid-prop-types': 0,
+    'react/jsx-filename-extension': [1, { extensions: ['.jsx', '.tsx'] }],
+    'react/jsx-no-bind': 0,
+    'react/no-array-index-key': 0,
+    'react/no-string-refs': 0,
+    'react/no-unescaped-entities': 0,
+    'react/no-unused-prop-types': 0,
+    'react/require-default-props': 0,
+    'react/jsx-fragments': 1,
+    'react/prop-types': 0,
+    'prettier/prettier': 'error',
+  },
+  settings: {
+    'import/resolver': 'webpack',
+    react: {
+      version: 'detect',
+    },
+  },
+};
diff --git a/superset-frontend/package-lock.json 
b/superset-frontend/package-lock.json
index 6dd4db4..6d40634 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -4724,6 +4724,11 @@
         }
       }
     },
+    "@types/classnames": {
+      "version": "2.2.9",
+      "resolved": 
"https://registry.npmjs.org/@types/classnames/-/classnames-2.2.9.tgz";,
+      "integrity": 
"sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A=="
+    },
     "@types/clone": {
       "version": "0.1.30",
       "resolved": "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz";,
@@ -4765,6 +4770,12 @@
         "@types/trusted-types": "*"
       }
     },
+    "@types/eslint-visitor-keys": {
+      "version": "1.0.0",
+      "resolved": 
"https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz";,
+      "integrity": 
"sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
+      "dev": true
+    },
     "@types/events": {
       "version": "3.0.0",
       "resolved": 
"https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz";,
@@ -4842,6 +4853,12 @@
       "integrity": 
"sha512-DC8xTuW/6TYgvEg3HEXS7cu9OijFqprVDXXiOcdOKZCU/5PJNLZU37VVvmZHdtMiGOa8wAA/We+JzbdxFzQTRQ==",
       "dev": true
     },
+    "@types/json-schema": {
+      "version": "7.0.4",
+      "resolved": 
"https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz";,
+      "integrity": 
"sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
+      "dev": true
+    },
     "@types/lodash": {
       "version": "4.14.147",
       "resolved": 
"https://registry.npmjs.org/@types/lodash/-/lodash-4.14.147.tgz";,
@@ -5013,6 +5030,149 @@
       "integrity": 
"sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw==",
       "dev": true
     },
+    "@typescript-eslint/eslint-plugin": {
+      "version": "2.20.0",
+      "resolved": 
"https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.20.0.tgz";,
+      "integrity": 
"sha512-cimIdVDV3MakiGJqMXw51Xci6oEDEoPkvh8ggJe2IIzcc0fYqAxOXN6Vbeanahz6dLZq64W+40iUEc9g32FLDQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/experimental-utils": "2.20.0",
+        "eslint-utils": "^1.4.3",
+        "functional-red-black-tree": "^1.0.1",
+        "regexpp": "^3.0.0",
+        "tsutils": "^3.17.1"
+      },
+      "dependencies": {
+        "eslint-utils": {
+          "version": "1.4.3",
+          "resolved": 
"https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz";,
+          "integrity": 
"sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
+          "dev": true,
+          "requires": {
+            "eslint-visitor-keys": "^1.1.0"
+          }
+        },
+        "eslint-visitor-keys": {
+          "version": "1.1.0",
+          "resolved": 
"https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz";,
+          "integrity": 
"sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+          "dev": true
+        },
+        "regexpp": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz";,
+          "integrity": 
"sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
+          "dev": true
+        },
+        "tsutils": {
+          "version": "3.17.1",
+          "resolved": 
"https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz";,
+          "integrity": 
"sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.8.1"
+          }
+        }
+      }
+    },
+    "@typescript-eslint/experimental-utils": {
+      "version": "2.20.0",
+      "resolved": 
"https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.20.0.tgz";,
+      "integrity": 
"sha512-fEBy9xYrwG9hfBLFEwGW2lKwDRTmYzH3DwTmYbT+SMycmxAoPl0eGretnBFj/s+NfYBG63w/5c3lsvqqz5mYag==",
+      "dev": true,
+      "requires": {
+        "@types/json-schema": "^7.0.3",
+        "@typescript-eslint/typescript-estree": "2.20.0",
+        "eslint-scope": "^5.0.0"
+      }
+    },
+    "@typescript-eslint/parser": {
+      "version": "2.20.0",
+      "resolved": 
"https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.20.0.tgz";,
+      "integrity": 
"sha512-o8qsKaosLh2qhMZiHNtaHKTHyCHc3Triq6aMnwnWj7budm3xAY9owSZzV1uon5T9cWmJRJGzTFa90aex4m77Lw==",
+      "dev": true,
+      "requires": {
+        "@types/eslint-visitor-keys": "^1.0.0",
+        "@typescript-eslint/experimental-utils": "2.20.0",
+        "@typescript-eslint/typescript-estree": "2.20.0",
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "1.1.0",
+          "resolved": 
"https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz";,
+          "integrity": 
"sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+          "dev": true
+        }
+      }
+    },
+    "@typescript-eslint/typescript-estree": {
+      "version": "2.20.0",
+      "resolved": 
"https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.20.0.tgz";,
+      "integrity": 
"sha512-WlFk8QtI8pPaE7JGQGxU7nGcnk1ccKAJkhbVookv94ZcAef3m6oCE/jEDL6dGte3JcD7reKrA0o55XhBRiVT3A==",
+      "dev": true,
+      "requires": {
+        "debug": "^4.1.1",
+        "eslint-visitor-keys": "^1.1.0",
+        "glob": "^7.1.6",
+        "is-glob": "^4.0.1",
+        "lodash": "^4.17.15",
+        "semver": "^6.3.0",
+        "tsutils": "^3.17.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz";,
+          "integrity": 
"sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+          "dev": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "eslint-visitor-keys": {
+          "version": "1.1.0",
+          "resolved": 
"https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz";,
+          "integrity": 
"sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+          "dev": true
+        },
+        "glob": {
+          "version": "7.1.6",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz";,
+          "integrity": 
"sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.0.4",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz";,
+          "integrity": 
"sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+          "dev": true
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz";,
+          "integrity": 
"sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        },
+        "tsutils": {
+          "version": "3.17.1",
+          "resolved": 
"https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz";,
+          "integrity": 
"sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.8.1"
+          }
+        }
+      }
+    },
     "@vx/axis": {
       "version": "0.0.140",
       "resolved": "https://registry.npmjs.org/@vx/axis/-/axis-0.0.140.tgz";,
@@ -10615,12 +10775,12 @@
       }
     },
     "eslint-config-prettier": {
-      "version": "2.10.0",
-      "resolved": 
"https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-2.10.0.tgz";,
-      "integrity": 
"sha512-Mhl90VLucfBuhmcWBgbUNtgBiK955iCDK1+aHAz7QfDQF6wuzWZ6JjihZ3ejJoGlJWIuko7xLqNm8BA5uenKhA==",
+      "version": "6.10.0",
+      "resolved": 
"https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz";,
+      "integrity": 
"sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==",
       "dev": true,
       "requires": {
-        "get-stdin": "^5.0.1"
+        "get-stdin": "^6.0.0"
       }
     },
     "eslint-import-resolver-node": {
@@ -10814,13 +10974,12 @@
       "dev": true
     },
     "eslint-plugin-prettier": {
-      "version": "2.7.0",
-      "resolved": 
"https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz";,
-      "integrity": 
"sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==",
+      "version": "3.1.2",
+      "resolved": 
"https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz";,
+      "integrity": 
"sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==",
       "dev": true,
       "requires": {
-        "fast-diff": "^1.1.1",
-        "jest-docblock": "^21.0.0"
+        "prettier-linter-helpers": "^1.0.0"
       }
     },
     "eslint-plugin-react": {
@@ -12686,9 +12845,9 @@
       "dev": true
     },
     "get-stdin": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz";,
-      "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz";,
+      "integrity": 
"sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
       "dev": true
     },
     "get-stream": {
@@ -15007,12 +15166,6 @@
         }
       }
     },
-    "jest-docblock": {
-      "version": "21.2.0",
-      "resolved": 
"https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz";,
-      "integrity": 
"sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==",
-      "dev": true
-    },
     "jest-each": {
       "version": "24.8.0",
       "resolved": 
"https://registry.npmjs.org/jest-each/-/jest-each-24.8.0.tgz";,
@@ -20562,6 +20715,15 @@
       "integrity": 
"sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
       "dev": true
     },
+    "prettier-linter-helpers": {
+      "version": "1.0.0",
+      "resolved": 
"https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz";,
+      "integrity": 
"sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+      "dev": true,
+      "requires": {
+        "fast-diff": "^1.1.2"
+      }
+    },
     "pretty-format": {
       "version": "24.8.0",
       "resolved": 
"https://registry.npmjs.org/pretty-format/-/pretty-format-24.8.0.tgz";,
@@ -24496,93 +24658,6 @@
       "integrity": 
"sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
       "dev": true
     },
-    "tslint": {
-      "version": "5.20.1",
-      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz";,
-      "integrity": 
"sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "builtin-modules": "^1.1.1",
-        "chalk": "^2.3.0",
-        "commander": "^2.12.1",
-        "diff": "^4.0.1",
-        "glob": "^7.1.1",
-        "js-yaml": "^3.13.1",
-        "minimatch": "^3.0.4",
-        "mkdirp": "^0.5.1",
-        "resolve": "^1.3.2",
-        "semver": "^5.3.0",
-        "tslib": "^1.8.0",
-        "tsutils": "^2.29.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": 
"https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz";,
-          "integrity": 
"sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz";,
-          "integrity": 
"sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "diff": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz";,
-          "integrity": 
"sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": 
"https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz";,
-          "integrity": 
"sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "tslint-react": {
-      "version": "4.1.0",
-      "resolved": 
"https://registry.npmjs.org/tslint-react/-/tslint-react-4.1.0.tgz";,
-      "integrity": 
"sha512-Y7CbFn09X7Mpg6rc7t/WPbmjx9xPI8p1RsQyiGCLWgDR6sh3+IBSlT+bEkc0PSZcWwClOkqq2wPsID8Vep6szQ==",
-      "dev": true,
-      "requires": {
-        "tsutils": "^3.9.1"
-      },
-      "dependencies": {
-        "tsutils": {
-          "version": "3.17.1",
-          "resolved": 
"https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz";,
-          "integrity": 
"sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.8.1"
-          }
-        }
-      }
-    },
-    "tsutils": {
-      "version": "2.29.0",
-      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz";,
-      "integrity": 
"sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.8.1"
-      }
-    },
     "tty-browserify": {
       "version": "0.0.0",
       "resolved": 
"https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz";,
diff --git a/superset-frontend/package.json b/superset-frontend/package.json
index b294433..2ea7c6b 100644
--- a/superset-frontend/package.json
+++ b/superset-frontend/package.json
@@ -15,8 +15,8 @@
     "dev-server": "node --max_old_space_size=4096 
./node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode=development 
--progress",
     "prod": "node --max_old_space_size=4096 
./node_modules/webpack/bin/webpack.js --mode=production --colors --progress",
     "build": "cross-env NODE_OPTIONS=--max_old_space_size=8192 
NODE_ENV=production webpack --mode=production --colors --progress",
-    "lint": "eslint --ignore-path=.eslintignore --ext .js,.jsx . && tslint -c 
tslint.json ./{src,spec}/**/*.ts{,x}",
-    "lint-fix": "eslint --fix --ignore-path=.eslintignore --ext .js,.jsx . && 
tslint -c tslint.json --fix ./{src,spec}/**/*.ts{,x} && npm run clean-css",
+    "lint": "eslint --ignore-path=.eslintignore --ext .js,.jsx,.ts,.tsx .",
+    "lint-fix": "eslint --fix --ignore-path=.eslintignore --ext 
.js,.jsx,.ts,tsx . && npm run clean-css",
     "clean-css": "prettier --write 
'{src,stylesheets}/**/*.{css,less,sass,scss}'"
   },
   "repository": {
@@ -82,6 +82,7 @@
     "@superset-ui/query": "^0.12.2",
     "@superset-ui/time-format": "^0.12.4",
     "@superset-ui/translation": "^0.12.0",
+    "@types/classnames": "^2.2.9",
     "@types/react-json-tree": "^0.6.11",
     "@vx/responsive": "0.0.172",
     "abortcontroller-polyfill": "^1.1.9",
@@ -163,6 +164,8 @@
     "@types/react": "^16.4.18",
     "@types/react-dom": "^16.0.9",
     "@types/react-table": "^7.0.2",
+    "@typescript-eslint/eslint-plugin": "^2.20.0",
+    "@typescript-eslint/parser": "^2.20.0",
     "babel-core": "^7.0.0-bridge.0",
     "babel-eslint": "^10.0.3",
     "babel-jest": "^24.8.0",
@@ -180,14 +183,14 @@
     "enzyme-adapter-react-16": "^1.14.0",
     "eslint": "^6.2.2",
     "eslint-config-airbnb": "^15.0.1",
-    "eslint-config-prettier": "^2.9.0",
+    "eslint-config-prettier": "^6.10.0",
     "eslint-import-resolver-webpack": "^0.10.1",
     "eslint-plugin-cypress": "^2.0.1",
     "eslint-plugin-import": "^2.2.0",
     "eslint-plugin-jest": "^21.24.1",
     "eslint-plugin-jsx-a11y": "^5.1.1",
     "eslint-plugin-no-only-tests": "^2.0.1",
-    "eslint-plugin-prettier": "^2.6.0",
+    "eslint-plugin-prettier": "^3.1.2",
     "eslint-plugin-react": "^7.16.0",
     "exports-loader": "^0.7.0",
     "fetch-mock": "^7.0.0-alpha.6",
@@ -215,8 +218,6 @@
     "ts-jest": "^24.0.2",
     "ts-loader": "^5.4.5",
     "tslib": "^1.10.0",
-    "tslint": "^5.20.1",
-    "tslint-react": "^4.1.0",
     "typescript": "^3.5.3",
     "url-loader": "^1.0.1",
     "webpack": "^4.19.0",
diff --git a/superset-frontend/spec/javascripts/utils/safeStringify_spec.ts 
b/superset-frontend/spec/javascripts/utils/safeStringify_spec.ts
index 6a019a2..acf7748 100644
--- a/superset-frontend/spec/javascripts/utils/safeStringify_spec.ts
+++ b/superset-frontend/spec/javascripts/utils/safeStringify_spec.ts
@@ -40,7 +40,9 @@ describe('Stringify utility testing', () => {
     };
     expect(safeStringify(noncircular)).toEqual(JSON.stringify(noncircular));
     // Checking that it works with quick-deepish-copies as well.
-    
expect(JSON.parse(safeStringify(noncircular))).toEqual(JSON.parse(JSON.stringify(noncircular)));
+    expect(JSON.parse(safeStringify(noncircular))).toEqual(
+      JSON.parse(JSON.stringify(noncircular)),
+    );
   });
 
   it('handles simple circular json as expected', () => {
@@ -93,7 +95,9 @@ describe('Stringify utility testing', () => {
         e: {},
       },
     };
-    
expect(safeStringify(emptyObjectValues)).toEqual(JSON.stringify(emptyObjectValues));
+    expect(safeStringify(emptyObjectValues)).toEqual(
+      JSON.stringify(emptyObjectValues),
+    );
   });
 
   it('does not remove nested same keys', () => {
diff --git a/superset-frontend/src/SqlLab/components/Link.tsx 
b/superset-frontend/src/SqlLab/components/Link.tsx
index be1d836..22bec92 100644
--- a/superset-frontend/src/SqlLab/components/Link.tsx
+++ b/superset-frontend/src/SqlLab/components/Link.tsx
@@ -52,7 +52,7 @@ const Link = ({
   if (tooltip) {
     return (
       <OverlayTrigger
-        overlay={<Tooltip id='tooltip'>{tooltip}</Tooltip>}
+        overlay={<Tooltip id="tooltip">{tooltip}</Tooltip>}
         placement={placement}
         delayShow={300}
         delayHide={150}
diff --git a/superset-frontend/src/SqlLab/utils/sqlKeywords.ts 
b/superset-frontend/src/SqlLab/utils/sqlKeywords.ts
index cec4222..15afdb3 100644
--- a/superset-frontend/src/SqlLab/utils/sqlKeywords.ts
+++ b/superset-frontend/src/SqlLab/utils/sqlKeywords.ts
@@ -95,7 +95,7 @@ const SQL_DATA_TYPES = [
 
 const allKeywords = SQL_KEYWORDS.concat(SQL_DATA_TYPES);
 
-const sqlKeywords = allKeywords.map((keyword) => ({
+const sqlKeywords = allKeywords.map(keyword => ({
   meta: 'sql',
   name: keyword,
   score: SQL_KEYWORD_AUTOCOMPLETE_SCORE,
diff --git a/superset-frontend/src/components/ConfirmStatusChange.tsx 
b/superset-frontend/src/components/ConfirmStatusChange.tsx
index 6cce051..30d20a1 100644
--- a/superset-frontend/src/components/ConfirmStatusChange.tsx
+++ b/superset-frontend/src/components/ConfirmStatusChange.tsx
@@ -34,7 +34,6 @@ interface State {
   open: boolean;
 }
 export default class ConfirmStatusChange extends React.Component<Props, State> 
{
-
   public state = {
     callbackArgs: [],
     open: false,
@@ -42,33 +41,33 @@ export default class ConfirmStatusChange extends 
React.Component<Props, State> {
 
   public showConfirm = (...callbackArgs: any[]) => {
     // check if any args are DOM events, if so, call persist
-    callbackArgs.forEach((arg) => arg && typeof arg.persist === 'function' && 
arg.persist());
+    callbackArgs.forEach(
+      arg => arg && typeof arg.persist === 'function' && arg.persist(),
+    );
 
     this.setState({
       callbackArgs,
       open: true,
     });
-  }
+  };
 
   public hide = () => this.setState({ open: false, callbackArgs: [] });
 
   public confirm = () => {
     this.props.onConfirm(...this.state.callbackArgs);
     this.hide();
-  }
+  };
 
   public render() {
     return (
       <>
         {this.props.children && this.props.children(this.showConfirm)}
         <Modal show={this.state.open} onHide={this.hide}>
-          <Modal.Header closeButton={true} >{this.props.title}</Modal.Header>
-          <Modal.Body>
-            {this.props.description}
-          </Modal.Body>
+          <Modal.Header closeButton>{this.props.title}</Modal.Header>
+          <Modal.Body>{this.props.description}</Modal.Body>
           <Modal.Footer>
             <Button onClick={this.hide}>{t('Cancel')}</Button>
-            <Button bsStyle='danger' onClick={this.confirm}>
+            <Button bsStyle="danger" onClick={this.confirm}>
               {t('OK')}
             </Button>
           </Modal.Footer>
diff --git a/superset-frontend/src/components/ListView/ListView.tsx 
b/superset-frontend/src/components/ListView/ListView.tsx
index 5d3168e..f7810d3 100644
--- a/superset-frontend/src/components/ListView/ListView.tsx
+++ b/superset-frontend/src/components/ListView/ListView.tsx
@@ -31,7 +31,13 @@ import {
 import IndeterminateCheckbox from '../IndeterminateCheckbox';
 import './ListViewStyles.less';
 import TableCollection from './TableCollection';
-import { FetchDataConfig, FilterToggle, FilterType, FilterTypeMap, SortColumn 
} from './types';
+import {
+  FetchDataConfig,
+  FilterToggle,
+  FilterType,
+  FilterTypeMap,
+  SortColumn,
+} from './types';
 import { convertFilters, removeFromList, useListViewState } from './utils';
 
 interface Props {
@@ -45,7 +51,11 @@ interface Props {
   title?: string;
   initialSort?: SortColumn[];
   filterTypes?: FilterTypeMap;
-  bulkActions?: Array<{ key?: string, name: React.ReactNode, onSelect: (rows: 
any[]) => any }>;
+  bulkActions?: Array<{
+    key?: string;
+    name: React.ReactNode;
+    onSelect: (rows: any[]) => any;
+  }>;
 }
 
 const bulkSelectColumnConfig = {
@@ -102,7 +112,9 @@ const ListView: FunctionComponent<Props> = ({
     initialPageSize,
     initialSort,
   });
-  const filterableColumns = useMemo(() => columns.filter((c) => c.filterable), 
[columns]);
+  const filterableColumns = useMemo(() => columns.filter(c => c.filterable), [
+    columns,
+  ]);
   const filterable = Boolean(columns.length);
 
   const removeFilterAndApply = (index: number) => {
@@ -114,25 +126,26 @@ const ListView: FunctionComponent<Props> = ({
   return (
     <div className={`superset-list-view ${className}`}>
       {title && filterable && (
-        <div className='header'>
+        <div className="header">
           <Row>
             <Col md={10}>
               <h2>{t(title)}</h2>
             </Col>
             {filterable && (
               <Col md={2}>
-                <div className='filter-dropdown'>
+                <div className="filter-dropdown">
                   <DropdownButton
-                    id='filter-picker'
-                    bsSize='small'
+                    id="filter-picker"
+                    bsSize="small"
                     bsStyle={'default'}
-                    noCaret={true}
-                    title={(
+                    noCaret
+                    title={
                       <>
-                        <i className='fa fa-filter text-primary' />
-                        {'  '}{t('Filter List')}
+                        <i className="fa fa-filter text-primary" />
+                        {'  '}
+                        {t('Filter List')}
                       </>
-                    )}
+                    }
                   >
                     {filterableColumns
                       .map(({ id, accessor, Header }) => ({
@@ -143,8 +156,8 @@ const ListView: FunctionComponent<Props> = ({
                         <MenuItem
                           key={ft.id}
                           eventKey={ft}
-                          onSelect={
-                            (fltr: FilterToggle) => 
setFilterToggles([...filterToggles, fltr])
+                          onSelect={(fltr: FilterToggle) =>
+                            setFilterToggles([...filterToggles, fltr])
                           }
                         >
                           {ft.Header}
@@ -157,51 +170,54 @@ const ListView: FunctionComponent<Props> = ({
           </Row>
           <hr />
           {filterToggles.map((ft, i) => (
-            <div key={`${ft.Header}-${i}`} className='filter-inputs'>
+            <div key={`${ft.Header}-${i}`} className="filter-inputs">
               <Row>
-                <Col className='text-center filter-column' md={2}>
+                <Col className="text-center filter-column" md={2}>
                   <span>{ft.Header}</span>
                 </Col>
                 <Col md={2}>
                   <FormControl
-                    componentClass='select'
-                    bsSize='small'
+                    componentClass="select"
+                    bsSize="small"
                     value={ft.filterId}
-                    placeholder={filterTypes[ft.id] ? 
filterTypes[ft.id][0].name : ''}
+                    placeholder={
+                      filterTypes[ft.id] ? filterTypes[ft.id][0].name : ''
+                    }
                     onChange={(e: React.MouseEvent<HTMLInputElement>) =>
                       updateFilterToggle(i, { filterId: e.currentTarget.value 
})
                     }
                   >
-                    {filterTypes[ft.id] && filterTypes[ft.id].map(
-                      ({ name, operator }: FilterType) => (
-                        <option key={name} value={operator}>
-                          {name}
-                        </option>
-                      ),
-                    )}
+                    {filterTypes[ft.id] &&
+                      filterTypes[ft.id].map(
+                        ({ name, operator }: FilterType) => (
+                          <option key={name} value={operator}>
+                            {name}
+                          </option>
+                        ),
+                      )}
                   </FormControl>
                 </Col>
                 <Col md={1} />
                 <Col md={4}>
                   <FormControl
-                    type='text'
-                    bsSize='small'
+                    type="text"
+                    bsSize="small"
                     value={ft.value || ''}
-                    onChange={
-                      (e: React.KeyboardEvent<HTMLInputElement>) =>
-                        updateFilterToggle(i, {
-                          value: e.currentTarget.value,
-                        })
+                    onChange={(e: React.KeyboardEvent<HTMLInputElement>) =>
+                      updateFilterToggle(i, {
+                        value: e.currentTarget.value,
+                      })
                     }
                   />
                 </Col>
                 <Col md={1}>
                   <div
-                    className='filter-close'
-                    role='button'
+                    className="filter-close"
+                    role="button"
+                    tabIndex={0}
                     onClick={() => removeFilterAndApply(i)}
                   >
-                    <i className='fa fa-close text-primary' />
+                    <i className="fa fa-close text-primary" />
                   </div>
                 </Col>
               </Row>
@@ -214,11 +230,11 @@ const ListView: FunctionComponent<Props> = ({
                 <Col md={10} />
                 <Col md={2}>
                   <Button
-                    data-test='apply-filters'
-                    disabled={filtersApplied ? true : false}
-                    bsStyle='primary'
+                    data-test="apply-filters"
+                    disabled={!!filtersApplied}
+                    bsStyle="primary"
                     onClick={applyFilters}
-                    bsSize='small'
+                    bsSize="small"
                   >
                     {t('Apply')}
                   </Button>
@@ -228,9 +244,8 @@ const ListView: FunctionComponent<Props> = ({
             </>
           )}
         </div>
-      )
-      }
-      <div className='body'>
+      )}
+      <div className="body">
         <TableCollection
           getTableProps={getTableProps}
           getTableBodyProps={getTableBodyProps}
@@ -240,33 +255,33 @@ const ListView: FunctionComponent<Props> = ({
           loading={loading}
         />
       </div>
-      <div className='footer'>
+      <div className="footer">
         <Row>
           <Col md={2}>
-            <div className='form-actions-container'>
-              <div className='btn-group'>
+            <div className="form-actions-container">
+              <div className="btn-group">
                 {bulkActions.length > 0 && (
                   <DropdownButton
-                    id='bulk-actions'
-                    bsSize='small'
-                    bsStyle='default'
-                    noCaret={true}
-                    title={(
+                    id="bulk-actions"
+                    bsSize="small"
+                    bsStyle="default"
+                    noCaret
+                    title={
                       <>
-                        {t('Actions')} <span className='caret' />
+                        {t('Actions')} <span className="caret" />
                       </>
-                    )}
+                    }
                   >
-                    {bulkActions.map((action) => (
+                    {bulkActions.map(action => (
                       <MenuItem
                         id={action.name}
                         key={action.key || action.name}
                         eventKey={selectedFlatRows}
-                        onSelect={
-                          (selectedRows: typeof selectedFlatRows) => {
-                            action.onSelect(selectedRows.map((r: any) => 
r.original));
-                          }
-                        }
+                        onSelect={(selectedRows: typeof selectedFlatRows) => {
+                          action.onSelect(
+                            selectedRows.map((r: any) => r.original),
+                          );
+                        }}
                       >
                         {action.name}
                       </MenuItem>
@@ -276,7 +291,7 @@ const ListView: FunctionComponent<Props> = ({
               </div>
             </div>
           </Col>
-          <Col md={8} className='text-center'>
+          <Col md={8} className="text-center">
             <Pagination
               prev={canPreviousPage}
               first={pageIndex > 1}
@@ -284,23 +299,24 @@ const ListView: FunctionComponent<Props> = ({
               last={pageIndex < pageCount - 2}
               items={pageCount}
               activePage={pageIndex + 1}
-              ellipsis={true}
-              boundaryLinks={true}
+              ellipsis
+              boundaryLinks
               maxButtons={5}
               onSelect={(p: number) => gotoPage(p - 1)}
             />
           </Col>
           <Col md={2}>
-            <span className='pull-right'>
+            <span className="pull-right">
               {t('showing')}{' '}
               <strong>
-                {pageSize * pageIndex + (rows.length && 1)}-{pageSize * 
pageIndex + rows.length}
+                {pageSize * pageIndex + (rows.length && 1)}-
+                {pageSize * pageIndex + rows.length}
               </strong>{' '}
               {t('of')} <strong>{count}</strong>
             </span>
           </Col>
         </Row>
-      </div >
+      </div>
     </div>
   );
 };
diff --git a/superset-frontend/src/components/ListView/TableCollection.tsx 
b/superset-frontend/src/components/ListView/TableCollection.tsx
index 1baae15..d3fa085 100644
--- a/superset-frontend/src/components/ListView/TableCollection.tsx
+++ b/superset-frontend/src/components/ListView/TableCollection.tsx
@@ -17,6 +17,7 @@
  * under the License.
  */
 import React from 'react';
+import cx from 'classnames';
 import { Cell, HeaderGroup, Row } from 'react-table';
 
 interface Props<D extends object = {}> {
@@ -37,23 +38,24 @@ export default function TableCollection({
   loading,
 }: Props<any>) {
   return (
-    <table {...getTableProps()} className='table table-hover'>
+    <table {...getTableProps()} className="table table-hover">
       <thead>
-        {headerGroups.map((headerGroup) => (
+        {headerGroups.map(headerGroup => (
           <tr {...headerGroup.getHeaderGroupProps()}>
             {headerGroup.headers.map((column: any) => (
-              <th {...column.getHeaderProps(column.getSortByToggleProps())} 
data-test='sort-header'>
+              <th
+                {...column.getHeaderProps(column.getSortByToggleProps())}
+                data-test="sort-header"
+              >
                 {column.render('Header')}
                 {'  '}
                 {column.sortable && (
                   <i
-                    className={`text-primary fa fa-${
-                      column.isSorted
-                        ? column.isSortedDesc
-                          ? 'sort-down'
-                          : 'sort-up'
-                        : 'sort'
-                      }`}
+                    className={cx('text-primary fa', {
+                      'fa-sort': !column.isSorted,
+                      'fa-sort-down': column.isSorted && column.isSortedDesc,
+                      'fa-sort-up': column.isSorted && !column.isSortedDesc,
+                    })}
                   />
                 )}
               </th>
@@ -62,7 +64,7 @@ export default function TableCollection({
         ))}
       </thead>
       <tbody {...getTableBodyProps()}>
-        {rows.map((row) => {
+        {rows.map(row => {
           prepareRow(row);
           const loadingProps = loading ? { className: 'table-row-loader' } : 
{};
           return (
@@ -70,7 +72,9 @@ export default function TableCollection({
               {...row.getRowProps()}
               {...loadingProps}
               onMouseEnter={() => row.setState && row.setState({ hover: true 
})}
-              onMouseLeave={() => row.setState && row.setState({ hover: false 
})}
+              onMouseLeave={() =>
+                row.setState && row.setState({ hover: false })
+              }
             >
               {row.cells.map((cell: Cell<any>) => {
                 const columnCellProps = cell.column.cellProps || {};
diff --git a/superset-frontend/src/components/ListView/utils.ts 
b/superset-frontend/src/components/ListView/utils.ts
index cb0fdc8..371bdf1 100644
--- a/superset-frontend/src/components/ListView/utils.ts
+++ b/superset-frontend/src/components/ListView/utils.ts
@@ -55,7 +55,7 @@ function updateInList(list: any[], index: number, update: 
any): any[] {
 export function convertFilters(fts: FilterToggle[]) {
   return fts
     .filter((ft: FilterToggle) => ft.value)
-    .map((ft) => ({ value: null, filterId: ft.filterId || 'sw', ...ft }));
+    .map(ft => ({ value: null, filterId: ft.filterId || 'sw', ...ft }));
 }
 
 interface UseListViewConfig {
diff --git a/superset-frontend/src/dashboard/stylesheets/popover-menu.less 
b/superset-frontend/src/dashboard/stylesheets/popover-menu.less
index c1fc157..4d14ba1 100644
--- a/superset-frontend/src/dashboard/stylesheets/popover-menu.less
+++ b/superset-frontend/src/dashboard/stylesheets/popover-menu.less
@@ -51,7 +51,8 @@
   cursor: default;
   z-index: @z-index-max;
 
-  &, .menu-item {
+  &,
+  .menu-item {
     display: flex;
     flex-direction: row;
     align-items: center;
diff --git a/superset-frontend/src/utils/safeStringify.ts 
b/superset-frontend/src/utils/safeStringify.ts
index 230dd35..b398bde 100644
--- a/superset-frontend/src/utils/safeStringify.ts
+++ b/superset-frontend/src/utils/safeStringify.ts
@@ -31,10 +31,10 @@ export function safeStringify(object: any): string {
         // We've seen this object before
         try {
           // Quick deep copy to duplicate if this is a repeat rather than a 
circle.
-         return JSON.parse(JSON.stringify(value));
+          return JSON.parse(JSON.stringify(value));
         } catch (err) {
           // Discard key if value cannot be duplicated.
-         return;
+          return; // eslint-disable-line consistent-return
         }
       }
       // Store the value in our cache.
diff --git a/superset-frontend/src/views/chartList/ChartList.tsx 
b/superset-frontend/src/views/chartList/ChartList.tsx
index f90d8d7..34c260a 100644
--- a/superset-frontend/src/views/chartList/ChartList.tsx
+++ b/superset-frontend/src/views/chartList/ChartList.tsx
@@ -22,7 +22,7 @@ import moment from 'moment';
 import PropTypes from 'prop-types';
 import React from 'react';
 // @ts-ignore
-import { Button, Modal, Panel } from 'react-bootstrap';
+import { Panel } from 'react-bootstrap';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import ListView from 'src/components/ListView/ListView';
 import { FetchDataConfig, FilterTypeMap } from 'src/components/ListView/types';
@@ -55,20 +55,11 @@ interface Chart {
 }
 
 class ChartList extends React.PureComponent<Props, State> {
-
-  get canEdit() {
-    return this.hasPerm('can_edit');
-  }
-
-  get canDelete() {
-    return this.hasPerm('can_delete');
-  }
-
-  public static propTypes = {
+  static propTypes = {
     addDangerToast: PropTypes.func.isRequired,
   };
 
-  public state: State = {
+  state: State = {
     chartCount: 0,
     charts: [],
     filterTypes: {},
@@ -78,15 +69,34 @@ class ChartList extends React.PureComponent<Props, State> {
     permissions: [],
   };
 
-  public initialSort = [{ id: 'changed_on', desc: true }];
+  componentDidMount() {
+    SupersetClient.get({
+      endpoint: `/api/v1/chart/_info`,
+    }).then(({ json = {} }) => {
+      this.setState({
+        filterTypes: json.filters,
+        permissions: json.permissions,
+      });
+    });
+  }
+
+  get canEdit() {
+    return this.hasPerm('can_edit');
+  }
 
-  public columns = [
+  get canDelete() {
+    return this.hasPerm('can_delete');
+  }
+
+  initialSort = [{ id: 'changed_on', desc: true }];
+
+  columns = [
     {
       Cell: ({
         row: {
-          original: { url, slice_name },
+          original: { url, slice_name: sliceName },
         },
-      }: any) => <a href={url}>{slice_name}</a>,
+      }: any) => <a href={url}>{sliceName}</a>,
       Header: t('Chart'),
       accessor: 'slice_name',
       filterable: true,
@@ -95,9 +105,9 @@ class ChartList extends React.PureComponent<Props, State> {
     {
       Cell: ({
         row: {
-          original: { viz_type },
+          original: { viz_type: vizType },
         },
-      }: any) => viz_type,
+      }: any) => vizType,
       Header: t('Visualization Type'),
       accessor: 'viz_type',
       sortable: true,
@@ -105,9 +115,12 @@ class ChartList extends React.PureComponent<Props, State> {
     {
       Cell: ({
         row: {
-          original: { datasource_name_text, datasource_link },
+          original: {
+            datasource_name_text: dsNameTxt,
+            datasource_link: dsLink,
+          },
         },
-      }: any) => <a href={datasource_link}>{datasource_name_text}</a>,
+      }: any) => <a href={dsLink}>{dsNameTxt}</a>,
       Header: t('Datasource'),
       accessor: 'datasource_name_text',
       sortable: true,
@@ -115,9 +128,12 @@ class ChartList extends React.PureComponent<Props, State> {
     {
       Cell: ({
         row: {
-          original: { changed_by_name, changed_by_url },
+          original: {
+            changed_by_name: changedByName,
+            changed_by_url: changedByUrl,
+          },
         },
-      }: any) => <a href={changed_by_url}>{changed_by_name}</a>,
+      }: any) => <a href={changedByName}>{changedByUrl}</a>,
       Header: t('Creator'),
       accessor: 'creator',
       sortable: true,
@@ -125,11 +141,9 @@ class ChartList extends React.PureComponent<Props, State> {
     {
       Cell: ({
         row: {
-          original: { changed_on },
+          original: { changed_on: changedOn },
         },
-      }: any) => (
-          <span className='no-wrap'>{moment(changed_on).fromNow()}</span>
-        ),
+      }: any) => <span 
className="no-wrap">{moment(changedOn).fromNow()}</span>,
       Header: t('Last Modified'),
       accessor: 'changed_on',
       sortable: true,
@@ -143,31 +157,40 @@ class ChartList extends React.PureComponent<Props, State> 
{
         }
 
         return (
-          <span className={`actions ${state && state.hover ? '' : 
'invisible'}`}>
+          <span
+            className={`actions ${state && state.hover ? '' : 'invisible'}`}
+          >
             {this.canDelete && (
               <ConfirmStatusChange
                 title={t('Please Confirm')}
-                description={<>{t('Are you sure you want to delete')} 
<b>{original.slice_name}</b>?</>}
+                description={
+                  <>
+                    {t('Are you sure you want to delete')}{' '}
+                    <b>{original.slice_name}</b>?
+                  </>
+                }
                 onConfirm={handleDelete}
               >
-                {(confirmDelete) => (
+                {confirmDelete => (
                   <span
-                    role='button'
-                    className='action-button'
+                    role="button"
+                    tabIndex={0}
+                    className="action-button"
                     onClick={confirmDelete}
                   >
-                    <i className='fa fa-trash' />
+                    <i className="fa fa-trash" />
                   </span>
                 )}
               </ConfirmStatusChange>
             )}
             {this.canEdit && (
               <span
-                role='button'
-                className='action-button'
+                role="button"
+                tabIndex={0}
+                className="action-button"
                 onClick={handleEdit}
               >
-                <i className='fa fa-pencil' />
+                <i className="fa fa-pencil" />
               </span>
             )}
           </span>
@@ -178,37 +201,42 @@ class ChartList extends React.PureComponent<Props, State> 
{
     },
   ];
 
-  public hasPerm = (perm: string) => {
+  hasPerm = (perm: string) => {
     if (!this.state.permissions.length) {
       return false;
     }
 
-    return this.state.permissions.some((p) => p === perm);
-  }
+    return this.state.permissions.some(p => p === perm);
+  };
 
-  public handleChartEdit = ({ id }: { id: number }) => {
+  handleChartEdit = ({ id }: { id: number }) => {
     window.location.assign(`/chart/edit/${id}`);
-  }
+  };
 
-  public handleChartDelete = ({ id, slice_name }: Chart) => {
+  handleChartDelete = ({ id, slice_name: sliceName }: Chart) => {
     SupersetClient.delete({
       endpoint: `/api/v1/chart/${id}`,
     }).then(
-      (resp) => {
+      () => {
         const { lastFetchDataConfig } = this.state;
         if (lastFetchDataConfig) {
           this.fetchData(lastFetchDataConfig);
         }
-        this.props.addSuccessToast(t('Deleted: %(slice_name)', slice_name));
+        this.props.addSuccessToast(t('Deleted: %(slice_name)', sliceName));
       },
-      (err: any) => {
-        this.props.addDangerToast(t('There was an issue deleting: 
%(slice_name)', slice_name));
+      () => {
+        this.props.addDangerToast(
+          t('There was an issue deleting: %(slice_name)', sliceName),
+        );
       },
     );
-  }
-  public handleBulkDashboardDelete = (charts: Chart[]) => {
+  };
+
+  handleBulkDashboardDelete = (charts: Chart[]) => {
     SupersetClient.delete({
-      endpoint: `/api/v1/dashboard/?q=!(${charts.map(({ id }) => 
id).join(',')})`,
+      endpoint: `/api/v1/dashboard/?q=!(${charts
+        .map(({ id }) => id)
+        .join(',')})`,
     }).then(
       ({ json = {} }) => {
         const { lastFetchDataConfig } = this.state;
@@ -219,19 +247,16 @@ class ChartList extends React.PureComponent<Props, State> 
{
       },
       (err: any) => {
         console.error(err);
-        this.props.addDangerToast(t('There was an issue deleting the selected 
dashboards'));
+        this.props.addDangerToast(
+          t('There was an issue deleting the selected dashboards'),
+        );
       },
     );
-  }
+  };
 
-  public fetchData = ({
-    pageIndex,
-    pageSize,
-    sortBy,
-    filters,
-  }: FetchDataConfig) => {
+  fetchData = ({ pageIndex, pageSize, sortBy, filters }: FetchDataConfig) => {
     this.setState({ loading: true });
-    const filterExps = Object.keys(filters).map((fk) => ({
+    const filterExps = Object.keys(filters).map(fk => ({
       col: fk,
       opr: filters[fk].filterId,
       value: filters[fk].filterValue,
@@ -249,50 +274,48 @@ class ChartList extends React.PureComponent<Props, State> 
{
       endpoint: `/api/v1/chart/?q=${queryParams}`,
     })
       .then(({ json = {} }) => {
-        this.setState({ charts: json.result, chartCount: json.count, 
labelColumns: json.label_columns });
+        this.setState({
+          charts: json.result,
+          chartCount: json.count,
+          labelColumns: json.label_columns,
+        });
       })
       .catch(() => {
-        this.props.addDangerToast(
-          t('An error occurred while fetching Charts'),
-        );
+        this.props.addDangerToast(t('An error occurred while fetching 
Charts'));
       })
       .finally(() => {
         this.setState({ loading: false });
       });
-  }
-
-  public componentDidMount() {
-    SupersetClient.get({
-      endpoint: `/api/v1/chart/_info`,
-    })
-      .then(({ json = {} }) => {
-        this.setState({ filterTypes: json.filters, permissions: 
json.permissions });
-      });
-  }
+  };
 
-  public render() {
+  render() {
     const { charts, chartCount, loading, filterTypes } = this.state;
     return (
-      <div className='container welcome'>
+      <div className="container welcome">
         <Panel>
-
           <ConfirmStatusChange
             title={t('Please confirm')}
-            description={t('Are you sure you want to delete the selected 
charts?')}
+            description={t(
+              'Are you sure you want to delete the selected charts?',
+            )}
             onConfirm={this.handleBulkDashboardDelete}
           >
-            {(confirmDelete) => {
+            {confirmDelete => {
               const bulkActions = [];
               if (this.canDelete) {
                 bulkActions.push({
                   key: 'delete',
-                  name: <><i className='fa fa-trash' /> Delete</>,
+                  name: (
+                    <>
+                      <i className="fa fa-trash" /> Delete
+                    </>
+                  ),
                   onSelect: confirmDelete,
                 });
               }
               return (
                 <ListView
-                  className='chart-list-view'
+                  className="chart-list-view"
                   title={'Charts'}
                   columns={this.columns}
                   data={charts}
@@ -308,7 +331,7 @@ class ChartList extends React.PureComponent<Props, State> {
             }}
           </ConfirmStatusChange>
         </Panel>
-      </div >
+      </div>
     );
   }
 }
diff --git a/superset-frontend/src/views/dashboardList/DashboardList.tsx 
b/superset-frontend/src/views/dashboardList/DashboardList.tsx
index 695c7f1..929f0a3 100644
--- a/superset-frontend/src/views/dashboardList/DashboardList.tsx
+++ b/superset-frontend/src/views/dashboardList/DashboardList.tsx
@@ -22,7 +22,7 @@ import moment from 'moment';
 import PropTypes from 'prop-types';
 import React from 'react';
 // @ts-ignore
-import { Button, Modal, Panel } from 'react-bootstrap';
+import { Panel } from 'react-bootstrap';
 import ConfirmStatusChange from 'src/components/ConfirmStatusChange';
 import ListView from 'src/components/ListView/ListView';
 import { FetchDataConfig, FilterTypeMap } from 'src/components/ListView/types';
@@ -57,6 +57,30 @@ interface Dashboard {
 }
 
 class DashboardList extends React.PureComponent<Props, State> {
+  static propTypes = {
+    addDangerToast: PropTypes.func.isRequired,
+  };
+
+  state: State = {
+    dashboardCount: 0,
+    dashboards: [],
+    filterTypes: {},
+    labelColumns: {},
+    lastFetchDataConfig: null,
+    loading: false,
+    permissions: [],
+  };
+
+  componentDidMount() {
+    SupersetClient.get({
+      endpoint: `/api/v1/dashboard/_info`,
+    }).then(({ json = {} }) => {
+      this.setState({
+        filterTypes: json.filters,
+        permissions: json.permissions,
+      });
+    });
+  }
 
   get canEdit() {
     return this.hasPerm('can_edit');
@@ -70,29 +94,15 @@ class DashboardList extends React.PureComponent<Props, 
State> {
     return this.hasPerm('can_mulexport');
   }
 
-  public static propTypes = {
-    addDangerToast: PropTypes.func.isRequired,
-  };
-
-  public state: State = {
-    dashboardCount: 0,
-    dashboards: [],
-    filterTypes: {},
-    labelColumns: {},
-    lastFetchDataConfig: null,
-    loading: false,
-    permissions: [],
-  };
-
-  public initialSort = [{ id: 'changed_on', desc: true }];
+  initialSort = [{ id: 'changed_on', desc: true }];
 
-  public columns = [
+  columns = [
     {
       Cell: ({
         row: {
-          original: { url, dashboard_title },
+          original: { url, dashboard_title: dashboardTitle },
         },
-      }: any) => <a href={url}>{dashboard_title}</a>,
+      }: any) => <a href={url}>{dashboardTitle}</a>,
       Header: t('Title'),
       accessor: 'dashboard_title',
       filterable: true,
@@ -101,9 +111,12 @@ class DashboardList extends React.PureComponent<Props, 
State> {
     {
       Cell: ({
         row: {
-          original: { changed_by_name, changed_by_url },
+          original: {
+            changed_by_name: changedByName,
+            changed_by_url: changedByUrl,
+          },
         },
-      }: any) => <a href={changed_by_url}>{changed_by_name}</a>,
+      }: any) => <a href={changedByUrl}>{changedByName}</a>,
       Header: t('Changed By Name'),
       accessor: 'changed_by_fk',
       sortable: true,
@@ -114,8 +127,10 @@ class DashboardList extends React.PureComponent<Props, 
State> {
           original: { published },
         },
       }: any) => (
-          <span className='no-wrap'>{published ? <i className='fa fa-check' /> 
: ''}</span>
-        ),
+        <span className="no-wrap">
+          {published ? <i className="fa fa-check" /> : ''}
+        </span>
+      ),
       Header: t('Published'),
       accessor: 'published',
       sortable: true,
@@ -123,11 +138,9 @@ class DashboardList extends React.PureComponent<Props, 
State> {
     {
       Cell: ({
         row: {
-          original: { changed_on },
+          original: { changed_on: changedOn },
         },
-      }: any) => (
-          <span className='no-wrap'>{moment(changed_on).fromNow()}</span>
-        ),
+      }: any) => <span 
className="no-wrap">{moment(changedOn).fromNow()}</span>,
       Header: t('Changed On'),
       accessor: 'changed_on',
       sortable: true,
@@ -141,40 +154,50 @@ class DashboardList extends React.PureComponent<Props, 
State> {
           return null;
         }
         return (
-          <span className={`actions ${state && state.hover ? '' : 
'invisible'}`}>
+          <span
+            className={`actions ${state && state.hover ? '' : 'invisible'}`}
+          >
             {this.canDelete && (
               <ConfirmStatusChange
                 title={t('Please Confirm')}
-                description={<>{t('Are you sure you want to delete')} 
<b>{original.dashboard_title}</b>?</>}
+                description={
+                  <>
+                    {t('Are you sure you want to delete')}{' '}
+                    <b>{original.dashboard_title}</b>?
+                  </>
+                }
                 onConfirm={handleDelete}
               >
-                {(confirmDelete) => (
+                {confirmDelete => (
                   <span
-                    role='button'
-                    className='action-button'
+                    role="button"
+                    tabIndex={0}
+                    className="action-button"
                     onClick={confirmDelete}
                   >
-                    <i className='fa fa-trash' />
+                    <i className="fa fa-trash" />
                   </span>
                 )}
               </ConfirmStatusChange>
             )}
             {this.canExport && (
               <span
-                role='button'
-                className='action-button'
+                role="button"
+                tabIndex={0}
+                className="action-button"
                 onClick={handleExport}
               >
-                <i className='fa fa-database' />
+                <i className="fa fa-database" />
               </span>
             )}
             {this.canEdit && (
               <span
-                role='button'
-                className='action-button'
+                role="button"
+                tabIndex={0}
+                className="action-button"
                 onClick={handleEdit}
               >
-                <i className='fa fa-pencil' />
+                <i className="fa fa-pencil" />
               </span>
             )}
           </span>
@@ -185,12 +208,23 @@ class DashboardList extends React.PureComponent<Props, 
State> {
     },
   ];
 
-  public handleDashboardEdit = ({ id }: { id: number }) => {
+  hasPerm = (perm: string) => {
+    if (!this.state.permissions.length) {
+      return false;
+    }
+
+    return Boolean(this.state.permissions.find(p => p === perm));
+  };
+
+  handleDashboardEdit = ({ id }: { id: number }) => {
     window.location.assign(`/dashboard/edit/${id}`);
-  }
+  };
 
-  public handleDashboardDelete = ({ id, dashboard_title }: Dashboard) => {
-    return SupersetClient.delete({
+  handleDashboardDelete = ({
+    id,
+    dashboard_title: dashboardTitle,
+  }: Dashboard) =>
+    SupersetClient.delete({
       endpoint: `/api/v1/dashboard/${id}`,
     }).then(
       () => {
@@ -198,18 +232,21 @@ class DashboardList extends React.PureComponent<Props, 
State> {
         if (lastFetchDataConfig) {
           this.fetchData(lastFetchDataConfig);
         }
-        this.props.addSuccessToast(t('Deleted') + ` ${dashboard_title}`);
+        this.props.addSuccessToast(`${t('Deleted')} ${dashboardTitle}`);
       },
       (err: any) => {
         console.error(err);
-        this.props.addDangerToast(t('There was an issue deleting') + 
`${dashboard_title}`);
+        this.props.addDangerToast(
+          `${t('There was an issue deleting')}${dashboardTitle}`,
+        );
       },
     );
-  }
 
-  public handleBulkDashboardDelete = (dashboards: Dashboard[]) => {
+  handleBulkDashboardDelete = (dashboards: Dashboard[]) => {
     SupersetClient.delete({
-      endpoint: `/api/v1/dashboard/?q=!(${dashboards.map(({ id }) => 
id).join(',')})`,
+      endpoint: `/api/v1/dashboard/?q=!(${dashboards
+        .map(({ id }) => id)
+        .join(',')})`,
     }).then(
       ({ json = {} }) => {
         const { lastFetchDataConfig } = this.state;
@@ -220,21 +257,20 @@ class DashboardList extends React.PureComponent<Props, 
State> {
       },
       (err: any) => {
         console.error(err);
-        this.props.addDangerToast(t('There was an issue deleting the selected 
dashboards'));
+        this.props.addDangerToast(
+          t('There was an issue deleting the selected dashboards'),
+        );
       },
     );
-  }
+  };
 
-  public handleBulkDashboardExport = (dashboards: Dashboard[]) => {
-    return window.location.href = `/ api / v1 / dashboard 
/export/?q=!(${dashboards.map(({ id }) => id).join(',')})`;
-  }
+  handleBulkDashboardExport = (dashboards: Dashboard[]) => {
+    window.location.href = `/api/v1/dashboard/export/?q=!(${dashboards
+      .map(({ id }) => id)
+      .join(',')})`;
+  };
 
-  public fetchData = ({
-    pageIndex,
-    pageSize,
-    sortBy,
-    filters,
-  }: FetchDataConfig) => {
+  fetchData = ({ pageIndex, pageSize, sortBy, filters }: FetchDataConfig) => {
     // set loading state, cache the last config for fetching data in this 
component.
     this.setState({
       lastFetchDataConfig: {
@@ -263,7 +299,11 @@ class DashboardList extends React.PureComponent<Props, 
State> {
       endpoint: `/api/v1/dashboard/?q=${queryParams}`,
     })
       .then(({ json = {} }) => {
-        this.setState({ dashboards: json.result, dashboardCount: json.count, 
labelColumns: json.label_columns });
+        this.setState({
+          dashboards: json.result,
+          dashboardCount: json.count,
+          labelColumns: json.label_columns,
+        });
       })
       .catch(() => {
         this.props.addDangerToast(
@@ -273,46 +313,47 @@ class DashboardList extends React.PureComponent<Props, 
State> {
       .finally(() => {
         this.setState({ loading: false });
       });
-  }
-
-  public componentDidMount() {
-    SupersetClient.get({
-      endpoint: `/api/v1/dashboard/_info`,
-    })
-      .then(({ json = {} }) => {
-        this.setState({ filterTypes: json.filters, permissions: 
json.permissions });
-      });
-  }
+  };
 
-  public render() {
+  render() {
     const { dashboards, dashboardCount, loading, filterTypes } = this.state;
     return (
-      <div className='container welcome' >
+      <div className="container welcome">
         <Panel>
           <ConfirmStatusChange
             title={t('Please confirm')}
-            description={t('Are you sure you want to delete the selected 
dashboards?')}
+            description={t(
+              'Are you sure you want to delete the selected dashboards?',
+            )}
             onConfirm={this.handleBulkDashboardDelete}
           >
-            {(confirmDelete) => {
+            {confirmDelete => {
               const bulkActions = [];
               if (this.canDelete) {
                 bulkActions.push({
                   key: 'delete',
-                  name: <><i className='fa fa-trash' /> Delete</>,
+                  name: (
+                    <>
+                      <i className="fa fa-trash" /> Delete
+                    </>
+                  ),
                   onSelect: confirmDelete,
                 });
               }
               if (this.canExport) {
                 bulkActions.push({
                   key: 'export',
-                  name: <><i className='fa fa-database' /> Export</>,
+                  name: (
+                    <>
+                      <i className="fa fa-database" /> Export
+                    </>
+                  ),
                   onSelect: this.handleBulkDashboardExport,
                 });
               }
               return (
                 <ListView
-                  className='dashboard-list-view'
+                  className="dashboard-list-view"
                   title={'Dashboards'}
                   columns={this.columns}
                   data={dashboards}
@@ -331,14 +372,6 @@ class DashboardList extends React.PureComponent<Props, 
State> {
       </div>
     );
   }
-
-  private hasPerm = (perm: string) => {
-    if (!this.state.permissions.length) {
-      return false;
-    }
-
-    return Boolean(this.state.permissions.find((p) => p === perm));
-  }
 }
 
 export default withToasts(DashboardList);
diff --git a/superset-frontend/tsconfig.json b/superset-frontend/tsconfig.json
index 6a505fa..0ab027c 100644
--- a/superset-frontend/tsconfig.json
+++ b/superset-frontend/tsconfig.json
@@ -1,24 +1,26 @@
 {
   "compilerOptions": {
-    "baseUrl": ".",
-    "outDir": "./dist",
-    "module": "commonjs",
-    "target": "es5",
-    "lib": ["es6", "dom", "es2018.promise"],
-    "sourceMap": true,
     "allowJs": true,
+    "allowSyntheticDefaultImports": true,
+    "baseUrl": ".",
+    "esModuleInterop": true,
+    "forceConsistentCasingInFileNames": true,
+    "importHelpers": true,
     "jsx": "react",
+    "lib": ["dom", "esnext"],
+    "module": "esnext",
     "moduleResolution": "node",
-    "forceConsistentCasingInFileNames": true,
+    "noImplicitAny": true,
     "noImplicitReturns": true,
     "noImplicitThis": true,
-    "noImplicitAny": true,
-    "importHelpers": true,
-    "strictNullChecks": true,
-    "suppressImplicitAnyIndexErrors": true,
     "noUnusedLocals": true,
+    "outDir": "./dist",
+    "pretty": true,
     "skipLibCheck": true,
-    "esModuleInterop": true
+    "sourceMap": true,
+    "strictNullChecks": true,
+    "suppressImplicitAnyIndexErrors": true,
+    "target": "es5"
   },
   "include": ["./src/**/*", "./spec/**/*"]
 }
diff --git a/superset-frontend/tslint.json b/superset-frontend/tslint.json
deleted file mode 100644
index bd9c88f..0000000
--- a/superset-frontend/tslint.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-  "extends": ["tslint:recommended", "tslint-react"],
-  "jsRules": {
-    "no-console": false
-  },
-  "rules": {
-    "interface-name": [true, "never-prefix"],
-    "quotemark": [true, "single"],
-    "jsx-no-multiline-js": false,
-    "jsx-no-lambda": false,
-    "no-console": false
-  },
-  "rulesDirectory": []
-}

Reply via email to