deprecate tslint and configure eslint for typescript (#9172)
This commit is contained in:
parent
e55fe43ca6
commit
74423e5d19
|
|
@ -26,3 +26,4 @@ vendor/*
|
|||
docs/*
|
||||
src/dashboard/deprecated/*
|
||||
**/node_modules
|
||||
*.d.ts
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 || {};
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -51,7 +51,8 @@
|
|||
cursor: default;
|
||||
z-index: @z-index-max;
|
||||
|
||||
&, .menu-item {
|
||||
&,
|
||||
.menu-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public columns = [
|
||||
get canEdit() {
|
||||
return this.hasPerm('can_edit');
|
||||
}
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
initialSort = [{ id: 'changed_on', desc: true }];
|
||||
|
||||
public state: State = {
|
||||
dashboardCount: 0,
|
||||
dashboards: [],
|
||||
filterTypes: {},
|
||||
labelColumns: {},
|
||||
lastFetchDataConfig: null,
|
||||
loading: false,
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
public 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 }) => {
|
||||
window.location.assign(`/dashboard/edit/${id}`);
|
||||
}
|
||||
hasPerm = (perm: string) => {
|
||||
if (!this.state.permissions.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public handleDashboardDelete = ({ id, dashboard_title }: Dashboard) => {
|
||||
return SupersetClient.delete({
|
||||
return Boolean(this.state.permissions.find(p => p === perm));
|
||||
};
|
||||
|
||||
handleDashboardEdit = ({ id }: { id: number }) => {
|
||||
window.location.assign(`/dashboard/edit/${id}`);
|
||||
};
|
||||
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -1,24 +1,26 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"outDir": "./dist",
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom", "es2018.promise"],
|
||||
"sourceMap": true,
|
||||
"allowJs": true,
|
||||
"jsx": "react",
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": ".",
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"importHelpers": true,
|
||||
"jsx": "react",
|
||||
"lib": ["dom", "esnext"],
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noImplicitAny": true,
|
||||
"importHelpers": true,
|
||||
"noUnusedLocals": true,
|
||||
"outDir": "./dist",
|
||||
"pretty": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strictNullChecks": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"noUnusedLocals": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true
|
||||
"target": "es5"
|
||||
},
|
||||
"include": ["./src/**/*", "./spec/**/*"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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": []
|
||||
}
|
||||
Loading…
Reference in New Issue