From commits-return-1103-archive-asf-public=cust-asf.ponee.io@superset.incubator.apache.org Tue Jun 19 00:43:24 2018 Return-Path: X-Original-To: archive-asf-public@cust-asf.ponee.io Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx-eu-01.ponee.io (Postfix) with SMTP id 59648180663 for ; Tue, 19 Jun 2018 00:43:22 +0200 (CEST) Received: (qmail 81298 invoked by uid 500); 18 Jun 2018 22:43:21 -0000 Mailing-List: contact commits-help@superset.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@superset.incubator.apache.org Delivered-To: mailing list commits@superset.incubator.apache.org Received: (qmail 81289 invoked by uid 99); 18 Jun 2018 22:43:21 -0000 Received: from ec2-52-202-80-70.compute-1.amazonaws.com (HELO gitbox.apache.org) (52.202.80.70) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 18 Jun 2018 22:43:21 +0000 Received: by gitbox.apache.org (ASF Mail Server at gitbox.apache.org, from userid 33) id B1828857AC; Mon, 18 Jun 2018 22:43:20 +0000 (UTC) Date: Mon, 18 Jun 2018 22:43:20 +0000 To: "commits@superset.apache.org" Subject: [incubator-superset] branch master updated: [adhoc-filters] Adding adhoc-filters to all viz types (#5206) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Message-ID: <152936180046.18768.14306993347387211023@gitbox.apache.org> From: johnbodley@apache.org X-Git-Host: gitbox.apache.org X-Git-Repo: incubator-superset X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 1fc4ee0d3c13672e122ee3f2c139e6fb307eb83f X-Git-Newrev: d483ed121ca0fc5b90eac65f5e39cd6cc9359331 X-Git-Rev: d483ed121ca0fc5b90eac65f5e39cd6cc9359331 X-Git-NotificationType: ref_changed_plus_diff X-Git-Multimail-Version: 1.5.dev Auto-Submitted: auto-generated This is an automated email from the ASF dual-hosted git repository. johnbodley 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 d483ed1 [adhoc-filters] Adding adhoc-filters to all viz types (#5206) d483ed1 is described below commit d483ed121ca0fc5b90eac65f5e39cd6cc9359331 Author: John Bodley <4567245+john-bodley@users.noreply.github.com> AuthorDate: Mon Jun 18 15:43:18 2018 -0700 [adhoc-filters] Adding adhoc-filters to all viz types (#5206) --- babel-node | 0 package-lock.json | 743 +++++++++++++++++++++ superset/assets/backendSync.json | 24 - .../components/AlteredSliceTag_spec.jsx | 80 ++- .../explore/components/AdhocFilterControl_spec.jsx | 52 -- .../components/ControlPanelsContainer_spec.jsx | 2 +- .../explore/components/FilterControl_spec.jsx | 248 ------- .../javascripts/explore/components/Filter_spec.jsx | 115 ---- superset/assets/src/components/AlteredSliceTag.jsx | 12 +- .../components/controls/AdhocFilterControl.jsx | 78 +-- .../src/explore/components/controls/Filter.jsx | 187 ------ .../explore/components/controls/FilterControl.jsx | 155 ----- .../src/explore/components/controls/index.js | 2 - superset/assets/src/explore/controls.jsx | 50 -- superset/assets/src/explore/store.js | 8 - superset/assets/src/explore/visTypes.js | 128 ++-- .../versions/bddc498dd179_adhoc_filters.py | 97 +++ superset/translations/de/LC_MESSAGES/messages.po | 1 - superset/translations/en/LC_MESSAGES/messages.po | 1 - superset/translations/es/LC_MESSAGES/messages.po | 1 - superset/translations/fr/LC_MESSAGES/messages.po | 1 - superset/translations/it/LC_MESSAGES/messages.po | 1 - superset/translations/ja/LC_MESSAGES/messages.po | 1 - superset/translations/messages.pot | 1 - .../translations/pt_BR/LC_MESSAGES/messages.po | 1 - superset/translations/ru/LC_MESSAGES/messages.po | 1 - superset/translations/zh/LC_MESSAGES/messages.po | 1 - superset/utils.py | 1 - 28 files changed, 1012 insertions(+), 980 deletions(-) diff --git a/babel-node b/babel-node new file mode 100644 index 0000000..e69de29 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..dea4bad --- /dev/null +++ b/package-lock.json @@ -0,0 +1,743 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "^1.1.3", + "esutils": "^2.0.2", + "js-tokens": "^3.0.2" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "requires": { + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "requires": { + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-1.2.0.tgz", + "integrity": "sha512-yeDwKaLgGdTpXL7RgGt5r6T4LmnTza/hUn5Ul8uZSGGMtEjYo13Nxai7SQaGCTEzUtg9Zq9qJn0EjEr7SeSlTQ==", + "requires": { + "babel-plugin-syntax-dynamic-import": "^6.18.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-dynamic-import": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz", + "integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=" + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "^6.24.1", + "babel-plugin-syntax-async-functions": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "lodash": "^4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "requires": { + "babel-helper-define-map": "^6.24.1", + "babel-helper-function-name": "^6.24.1", + "babel-helper-optimise-call-expression": "^6.24.1", + "babel-helper-replace-supers": "^6.24.1", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "requires": { + "babel-helper-function-name": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.2", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", + "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "requires": { + "babel-plugin-transform-strict-mode": "^6.24.1", + "babel-runtime": "^6.26.0", + "babel-template": "^6.26.0", + "babel-types": "^6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "requires": { + "babel-helper-hoist-variables": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "requires": { + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "requires": { + "babel-helper-replace-supers": "^6.24.1", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "requires": { + "babel-helper-call-delegate": "^6.24.1", + "babel-helper-get-function-arity": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-template": "^6.24.1", + "babel-traverse": "^6.24.1", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "requires": { + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "requires": { + "babel-helper-regex": "^6.24.1", + "babel-runtime": "^6.22.0", + "regexpu-core": "^2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1", + "babel-plugin-syntax-exponentiation-operator": "^6.8.0", + "babel-runtime": "^6.22.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "requires": { + "regenerator-transform": "^0.10.0" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "requires": { + "babel-runtime": "^6.22.0", + "babel-types": "^6.24.1" + } + }, + "babel-preset-env": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz", + "integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-syntax-trailing-function-commas": "^6.22.0", + "babel-plugin-transform-async-to-generator": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.23.0", + "babel-plugin-transform-es2015-classes": "^6.23.0", + "babel-plugin-transform-es2015-computed-properties": "^6.22.0", + "babel-plugin-transform-es2015-destructuring": "^6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.22.0", + "babel-plugin-transform-es2015-for-of": "^6.23.0", + "babel-plugin-transform-es2015-function-name": "^6.22.0", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.22.0", + "babel-plugin-transform-es2015-modules-commonjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-systemjs": "^6.23.0", + "babel-plugin-transform-es2015-modules-umd": "^6.23.0", + "babel-plugin-transform-es2015-object-super": "^6.22.0", + "babel-plugin-transform-es2015-parameters": "^6.23.0", + "babel-plugin-transform-es2015-shorthand-properties": "^6.22.0", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.22.0", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.22.0", + "babel-plugin-transform-exponentiation-operator": "^6.22.0", + "babel-plugin-transform-regenerator": "^6.22.0", + "browserslist": "^3.2.6", + "invariant": "^2.2.2", + "semver": "^5.3.0" + } + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "requires": { + "babel-plugin-check-es2015-constants": "^6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0", + "babel-plugin-transform-es2015-block-scoping": "^6.24.1", + "babel-plugin-transform-es2015-classes": "^6.24.1", + "babel-plugin-transform-es2015-computed-properties": "^6.24.1", + "babel-plugin-transform-es2015-destructuring": "^6.22.0", + "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1", + "babel-plugin-transform-es2015-for-of": "^6.22.0", + "babel-plugin-transform-es2015-function-name": "^6.24.1", + "babel-plugin-transform-es2015-literals": "^6.22.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1", + "babel-plugin-transform-es2015-modules-umd": "^6.24.1", + "babel-plugin-transform-es2015-object-super": "^6.24.1", + "babel-plugin-transform-es2015-parameters": "^6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1", + "babel-plugin-transform-es2015-spread": "^6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "^6.24.1", + "babel-plugin-transform-es2015-template-literals": "^6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0", + "babel-plugin-transform-es2015-unicode-regex": "^6.24.1", + "babel-plugin-transform-regenerator": "^6.24.1" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "requires": { + "babel-runtime": "^6.26.0", + "babel-traverse": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "lodash": "^4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "requires": { + "babel-code-frame": "^6.26.0", + "babel-messages": "^6.23.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "debug": "^2.6.8", + "globals": "^9.18.0", + "invariant": "^2.2.2", + "lodash": "^4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "browserslist": { + "version": "3.2.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz", + "integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000844", + "electron-to-chromium": "^1.3.47" + } + }, + "caniuse-lite": { + "version": "1.0.30000856", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000856.tgz", + "integrity": "sha512-x3mYcApHMQemyaHuH/RyqtKCGIYTgEA63fdi+VBvDz8xUSmRiVWTLeyKcoGQCGG6UPR9/+4qG4OKrTa6aSQRKg==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "core-js": { + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", + "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "electron-to-chromium": { + "version": "1.3.48", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.48.tgz", + "integrity": "sha1-07DYWTgUBE4JLs4hCPw6ya6kuQA=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "requires": { + "js-tokens": "^3.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==" + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "requires": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "requires": { + "regenerate": "^1.2.1", + "regjsgen": "^0.2.0", + "regjsparser": "^0.1.4" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "requires": { + "jsesc": "~0.5.0" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" + } + } +} diff --git a/superset/assets/backendSync.json b/superset/assets/backendSync.json index 9145cc9..9b82552 100644 --- a/superset/assets/backendSync.json +++ b/superset/assets/backendSync.json @@ -1683,18 +1683,6 @@ "renderTrigger": true, "default": "" }, - "where": { - "type": "TextControl", - "label": "Custom WHERE clause", - "default": "", - "description": "The text in this box gets included in your query's WHERE clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards." - }, - "having": { - "type": "TextControl", - "label": "Custom HAVING clause", - "default": "", - "description": "The text in this box gets included in your query's HAVING clause, as an AND to other criteria. You can include complex expression, parenthesis and anything else supported by the backend it is directed towards." - }, "compare_lag": { "type": "TextControl", "label": "Comparison Period Lag", @@ -2628,12 +2616,6 @@ "default": "", "description": "Labels for the marker lines" }, - "filters": { - "type": "FilterControl", - "label": "", - "default": [], - "description": "" - }, "annotation_layers": { "type": "AnnotationLayerControl", "label": "", @@ -2641,12 +2623,6 @@ "description": "Annotation Layers", "renderTrigger": true }, - "having_filters": { - "type": "FilterControl", - "label": "", - "default": [], - "description": "" - }, "slice_id": { "type": "HiddenControl", "label": "Slice ID", diff --git a/superset/assets/spec/javascripts/components/AlteredSliceTag_spec.jsx b/superset/assets/spec/javascripts/components/AlteredSliceTag_spec.jsx index 7994720..8670069 100644 --- a/superset/assets/spec/javascripts/components/AlteredSliceTag_spec.jsx +++ b/superset/assets/spec/javascripts/components/AlteredSliceTag_spec.jsx @@ -11,7 +11,15 @@ import TooltipWrapper from '../../../src/components/TooltipWrapper'; const defaultProps = { origFormData: { - filters: [{ col: 'a', op: '==', val: 'hello' }], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: 'hello', + expressionType: 'SIMPLE', + operator: '==', + subject: 'a', + }, + ], y_axis_bounds: [10, 20], column_collection: [{ 1: 'a', b: ['6', 'g'] }], bool: false, @@ -21,7 +29,15 @@ const defaultProps = { ever: { a: 'b', c: 'd' }, }, currentFormData: { - filters: [{ col: 'b', op: 'in', val: ['hello', 'my', 'name'] }], + adhoc_filters: [ + { + clause: 'WHERE', + comparator: ['hello', 'my', 'name'], + expressionType: 'SIMPLE', + operator: 'in', + subject: 'b', + }, + ], y_axis_bounds: [15, 16], column_collection: [{ 1: 'a', b: [9, '15'], t: 'gggg' }], bool: true, @@ -33,9 +49,25 @@ const defaultProps = { }; const expectedDiffs = { - filters: { - before: [{ col: 'a', op: '==', val: 'hello' }], - after: [{ col: 'b', op: 'in', val: ['hello', 'my', 'name'] }], + adhoc_filters: { + before: [ + { + clause: 'WHERE', + comparator: 'hello', + expressionType: 'SIMPLE', + operator: '==', + subject: 'a', + }, + ], + after: [ + { + clause: 'WHERE', + comparator: ['hello', 'my', 'name'], + expressionType: 'SIMPLE', + operator: 'in', + subject: 'b', + }, + ], }, y_axis_bounds: { before: [10, 20], @@ -211,25 +243,49 @@ describe('AlteredSliceTag', () => { }); it('returns "[]" for empty filters', () => { - expect(wrapper.instance().formatValue([], 'filters')).to.equal('[]'); + expect(wrapper.instance().formatValue([], 'adhoc_filters')).to.equal('[]'); }); it('correctly formats filters with array values', () => { const filters = [ - { col: 'a', op: 'in', val: ['1', 'g', '7', 'ho'] }, - { col: 'b', op: 'not in', val: ['hu', 'ho', 'ha'] }, + { + clause: 'WHERE', + comparator: ['1', 'g', '7', 'ho'], + expressionType: 'SIMPLE', + operator: 'in', + subject: 'a', + }, + { + clause: 'WHERE', + comparator: ['hu', 'ho', 'ha'], + expressionType: 'SIMPLE', + operator: 'not in', + subject: 'b', + }, ]; const expected = 'a in [1, g, 7, ho], b not in [hu, ho, ha]'; - expect(wrapper.instance().formatValue(filters, 'filters')).to.equal(expected); + expect(wrapper.instance().formatValue(filters, 'adhoc_filters')).to.equal(expected); }); it('correctly formats filters with string values', () => { const filters = [ - { col: 'a', op: '==', val: 'gucci' }, - { col: 'b', op: 'LIKE', val: 'moshi moshi' }, + { + clause: 'WHERE', + comparator: 'gucci', + expressionType: 'SIMPLE', + operator: '==', + subject: 'a', + }, + { + clause: 'WHERE', + comparator: 'moshi moshi', + expressionType: 'SIMPLE', + operator: 'LIKE', + subject: 'b', + }, ]; const expected = 'a == gucci, b LIKE moshi moshi'; - expect(wrapper.instance().formatValue(filters, 'filters')).to.equal(expected); + expect(wrapper.instance().formatValue(filters, 'adhoc_filters')).to.equal(expected); }); }); }); diff --git a/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx index 4be8a2e..2123ed7 100644 --- a/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx @@ -33,18 +33,9 @@ const columns = [ { type: 'DOUBLE', column_name: 'value' }, ]; -const legacyFilter = { col: 'value', op: '>', val: '5' }; -const legacyHavingFilter = { col: 'SUM(value)', op: '>', val: '10' }; -const whereFilterText = 'target in (\'alpha\')'; -const havingFilterText = 'SUM(value) < 20'; - const formData = { - filters: [legacyFilter], - having: havingFilterText, - having_filters: [legacyHavingFilter], metric: undefined, metrics: [sumValueAdhocMetric, savedMetric.saved_metric_name], - where: whereFilterText, }; function setup(overrides) { @@ -68,49 +59,6 @@ describe('AdhocFilterControl', () => { expect(wrapper.find(OnPasteSelect)).to.have.lengthOf(1); }); - it('will translate legacy filters into adhoc filters if no adhoc filters are present', () => { - const { wrapper } = setup({ value: undefined }); - expect(wrapper.state('values')).to.have.lengthOf(4); - expect(wrapper.state('values')[0].equals(( - new AdhocFilter({ - expressionType: EXPRESSION_TYPES.SIMPLE, - subject: 'value', - operator: '>', - comparator: '5', - clause: CLAUSES.WHERE, - }) - ))).to.be.true; - expect(wrapper.state('values')[1].equals(( - new AdhocFilter({ - expressionType: EXPRESSION_TYPES.SIMPLE, - subject: 'SUM(value)', - operator: '>', - comparator: '10', - clause: CLAUSES.HAVING, - }) - ))).to.be.true; - expect(wrapper.state('values')[2].equals(( - new AdhocFilter({ - expressionType: EXPRESSION_TYPES.SQL, - sqlExpression: 'target in (\'alpha\')', - clause: CLAUSES.WHERE, - }) - ))).to.be.true; - expect(wrapper.state('values')[3].equals(( - new AdhocFilter({ - expressionType: EXPRESSION_TYPES.SQL, - sqlExpression: 'SUM(value) < 20', - clause: CLAUSES.HAVING, - }) - ))).to.be.true; - }); - - it('will ignore legacy filters if adhoc filters are present', () => { - const { wrapper } = setup(); - expect(wrapper.state('values')).to.have.lengthOf(1); - expect(wrapper.state('values')[0]).to.equal(simpleAdhocFilter); - }); - it('handles saved metrics being selected to filter on', () => { const { wrapper, onChange } = setup({ value: [] }); const select = wrapper.find(OnPasteSelect); diff --git a/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx b/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx index fb1ea61..64a657e 100644 --- a/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/ControlPanelsContainer_spec.jsx @@ -26,6 +26,6 @@ describe('ControlPanelsContainer', () => { }); it('renders ControlPanelSections', () => { - expect(wrapper.find(ControlPanelSection)).to.have.lengthOf(7); + expect(wrapper.find(ControlPanelSection)).to.have.lengthOf(6); }); }); diff --git a/superset/assets/spec/javascripts/explore/components/FilterControl_spec.jsx b/superset/assets/spec/javascripts/explore/components/FilterControl_spec.jsx deleted file mode 100644 index 2b83fff..0000000 --- a/superset/assets/spec/javascripts/explore/components/FilterControl_spec.jsx +++ /dev/null @@ -1,248 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import React from 'react'; -import { Button } from 'react-bootstrap'; -import sinon from 'sinon'; -import { expect } from 'chai'; -import { describe, it, beforeEach } from 'mocha'; -import { shallow } from 'enzyme'; -import FilterControl from '../../../../src/explore/components/controls/FilterControl'; -import Filter from '../../../../src/explore/components/controls/Filter'; - -const $ = window.$ = require('jquery'); - -const defaultProps = { - name: 'not_having_filters', - onChange: sinon.spy(), - value: [ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd'], - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - ], - datasource: { - id: 1, - type: 'qtable', - filter_select: true, - filterable_cols: [['col1', 'col2']], - metrics_combo: [ - ['m1', 'v1'], - ['m2', 'v2'], - ], - }, -}; - -describe('FilterControl', () => { - let wrapper; - - beforeEach(() => { - wrapper = shallow(); - wrapper.setState({ - filters: [ - { - valuesLoading: false, - valueChoices: ['a', 'b', 'c', 'd', 'e', 'f'], - }, - { - valuesLoading: false, - valueChoices: ['X', 'Y', 'Z'], - }, - // Need a duplicate since onChange calls are not changing props - { - valuesLoading: false, - valueChoices: ['X', 'Y', 'Z'], - }, - ], - }); - }); - - it('renders Filters', () => { - expect( - React.isValidElement(), - ).to.equal(true); - }); - - it('renders one button and two filters', () => { - expect(wrapper.find(Filter)).to.have.lengthOf(2); - expect(wrapper.find(Button)).to.have.lengthOf(1); - }); - - it('adds filter when clicking Add Filter', () => { - const addButton = wrapper.find('#add-button'); - expect(addButton).to.have.lengthOf(1); - addButton.simulate('click'); - expect(defaultProps.onChange).to.have.property('callCount', 1); - expect(defaultProps.onChange.getCall(0).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd'], - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - { - col: 'col1', - op: 'in', - val: [], - }, - ]); - }); - - it('removes a the second filter when its delete button is clicked', () => { - expect(wrapper.find(Filter)).to.have.lengthOf(2); - wrapper.instance().removeFilter(1); - expect(defaultProps.onChange).to.have.property('callCount', 2); - expect(defaultProps.onChange.getCall(1).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd'], - }, - ]); - }); - - before(() => { - sinon.stub($, 'ajax'); - }); - - after(() => { - $.ajax.restore(); - }); - - it('makes a GET request to retrieve value choices', () => { - wrapper.instance().fetchFilterValues(0, 'col1'); - expect($.ajax.getCall(0).args[0].type).to.deep.equal('GET'); - expect($.ajax.getCall(0).args[0].url).to.deep.equal('/superset/filter/qtable/1/col1/'); - }); - - it('changes filter values when one is removed', () => { - wrapper.instance().changeFilter(0, 'val', ['a', 'b']); - expect(defaultProps.onChange).to.have.property('callCount', 3); - expect(defaultProps.onChange.getCall(2).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b'], - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - ]); - }); - - it('changes filter values when one is added', () => { - wrapper.instance().changeFilter(0, 'val', ['a', 'b', 'd', 'e']); - expect(defaultProps.onChange).to.have.property('callCount', 4); - expect(defaultProps.onChange.getCall(3).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd', 'e'], - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - ]); - }); - - it('changes op and transforms values', () => { - wrapper.instance().changeFilter(0, ['val', 'op'], ['a', '==']); - wrapper.instance().changeFilter(1, ['val', 'op'], [['Z'], 'in']); - expect(defaultProps.onChange).to.have.property('callCount', 6); - expect(defaultProps.onChange.getCall(4).args[0]).to.deep.equal([ - { - col: 'col1', - op: '==', - val: 'a', - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - ]); - expect(defaultProps.onChange.getCall(5).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd'], - }, - { - col: 'col2', - op: 'in', - val: ['Z'], - }, - ]); - }); - - it('changes column and clears invalid values', () => { - wrapper.instance().changeFilter(0, 'col', 'col2'); - expect(defaultProps.onChange).to.have.property('callCount', 7); - expect(defaultProps.onChange.getCall(6).args[0]).to.deep.equal([ - { - col: 'col2', - op: 'in', - val: [], - }, - { - col: 'col2', - op: '==', - val: 'Z', - }, - ]); - wrapper.instance().changeFilter(1, 'col', 'col1'); - expect(defaultProps.onChange).to.have.property('callCount', 8); - expect(defaultProps.onChange.getCall(7).args[0]).to.deep.equal([ - { - col: 'col1', - op: 'in', - val: ['a', 'b', 'd'], - }, - { - col: 'col1', - op: '==', - val: '', - }, - ]); - }); - - it('tracks an active filter select ajax request', () => { - const spyReq = sinon.spy(); - $.ajax.reset(); - $.ajax.onFirstCall().returns(spyReq); - wrapper.instance().fetchFilterValues(0, 'col1'); - expect(wrapper.state().activeRequest).to.equal(spyReq); - // Sets active to null after success - $.ajax.getCall(0).args[0].success(['opt1', 'opt2', null, '']); - expect(wrapper.state().filters[0].valuesLoading).to.equal(false); - expect(wrapper.state().filters[0].valueChoices).to.deep.equal(['opt1', 'opt2', null, '']); - expect(wrapper.state().activeRequest).to.equal(null); - }); - - - it('cancels active request if another is submitted', () => { - const spyReq = sinon.spy(); - spyReq.abort = sinon.spy(); - $.ajax.reset(); - $.ajax.onFirstCall().returns(spyReq); - wrapper.instance().fetchFilterValues(0, 'col1'); - expect(wrapper.state().activeRequest).to.equal(spyReq); - const spyReq1 = sinon.spy(); - $.ajax.onSecondCall().returns(spyReq1); - wrapper.instance().fetchFilterValues(1, 'col2'); - expect(spyReq.abort.called).to.equal(true); - expect(wrapper.state().activeRequest).to.equal(spyReq1); - }); -}); diff --git a/superset/assets/spec/javascripts/explore/components/Filter_spec.jsx b/superset/assets/spec/javascripts/explore/components/Filter_spec.jsx deleted file mode 100644 index 27425de..0000000 --- a/superset/assets/spec/javascripts/explore/components/Filter_spec.jsx +++ /dev/null @@ -1,115 +0,0 @@ -/* eslint-disable no-unused-expressions */ -import React from 'react'; -import Select from 'react-select'; -import { Button } from 'react-bootstrap'; -import sinon from 'sinon'; -import { expect } from 'chai'; -import { describe, it, beforeEach } from 'mocha'; -import { shallow } from 'enzyme'; -import Filter from '../../../../src/explore/components/controls/Filter'; -import SelectControl from '../../../../src/explore/components/controls/SelectControl'; - -const defaultProps = { - changeFilter: sinon.spy(), - removeFilter: () => {}, - filter: { - col: null, - op: 'in', - value: ['val'], - }, - datasource: { - id: 1, - type: 'qtable', - filter_select: false, - filterable_cols: ['col1', 'col2'], - metrics_combo: [ - ['m1', 'v1'], - ['m2', 'v2'], - ], - }, -}; - -describe('Filter', () => { - let wrapper; - - beforeEach(() => { - wrapper = shallow(); - }); - - it('renders Filters', () => { - expect( - React.isValidElement(), - ).to.equal(true); - }); - - it('renders two selects, one button and one input', () => { - expect(wrapper.find(Select)).to.have.lengthOf(2); - expect(wrapper.find(Button)).to.have.lengthOf(1); - expect(wrapper.find(SelectControl)).to.have.lengthOf(1); - expect(wrapper.find('#select-op').prop('options')).to.have.lengthOf(10); - }); - - it('renders five op choices for table datasource', () => { - const props = Object.assign({}, defaultProps); - props.datasource = { - id: 1, - type: 'druid', - filter_select: false, - filterable_cols: ['country_name'], - }; - const druidWrapper = shallow(); - expect(druidWrapper.find('#select-op').prop('options')).to.have.lengthOf(11); - }); - - it('renders six op choices for having filter', () => { - const props = Object.assign({}, defaultProps); - props.having = true; - const havingWrapper = shallow(); - expect(havingWrapper.find('#select-op').prop('options')).to.have.lengthOf(6); - }); - - it('calls changeFilter when select is changed', () => { - const selectCol = wrapper.find('#select-col'); - selectCol.simulate('change', { value: 'col' }); - const selectOp = wrapper.find('#select-op'); - selectOp.simulate('change', { value: 'in' }); - const selectVal = wrapper.find(SelectControl); - selectVal.simulate('change', { value: 'x' }); - expect(defaultProps.changeFilter).to.have.property('callCount', 3); - }); - - it('renders input for regex filters', () => { - const props = Object.assign({}, defaultProps); - props.filter = { - col: null, - op: 'regex', - value: 'val', - }; - const regexWrapper = shallow(); - expect(regexWrapper.find('input')).to.have.lengthOf(1); - }); - - it('renders `input` for text filters', () => { - const props = Object.assign({}, defaultProps); - ['>=', '>', '<=', '<'].forEach((op) => { - props.filter = { - col: 'col1', - op, - value: 'val', - }; - wrapper = shallow(); - expect(wrapper.find('input')).to.have.lengthOf(1); - }); - }); - - it('replaces null filter values with empty string in `input`', () => { - const props = Object.assign({}, defaultProps); - props.filter = { - col: 'col1', - op: '>=', - value: null, - }; - wrapper = shallow(); - expect(wrapper.find('input').props().value).to.equal(''); - }); -}); diff --git a/superset/assets/src/components/AlteredSliceTag.jsx b/superset/assets/src/components/AlteredSliceTag.jsx index 209e4a9..a317a04 100644 --- a/superset/assets/src/components/AlteredSliceTag.jsx +++ b/superset/assets/src/components/AlteredSliceTag.jsx @@ -42,6 +42,10 @@ export default class AlteredSliceTag extends React.Component { if (!ofd[fdKey] && !cfd[fdKey]) { continue; } + // Ignore obsolete legacy filters + if (['filters', 'having', 'having_filters', 'where'].includes(fdKey)) { + continue; + } if (!isEqual(ofd[fdKey], cfd[fdKey])) { diffs[fdKey] = { before: ofd[fdKey], after: cfd[fdKey] }; } @@ -56,13 +60,15 @@ export default class AlteredSliceTag extends React.Component { return 'N/A'; } else if (value === null) { return 'null'; - } else if (controls[key] && controls[key].type === 'FilterControl') { + } else if (controls[key] && controls[key].type === 'AdhocFilterControl') { if (!value.length) { return '[]'; } return value.map((v) => { - const filterVal = v.val && v.val.constructor === Array ? `[${v.val.join(', ')}]` : v.val; - return `${v.col} ${v.op} ${filterVal}`; + const filterVal = v.comparator && v.comparator.constructor === Array ? + `[${v.comparator.join(', ')}]` : + v.comparator; + return `${v.subject} ${v.operator} ${filterVal}`; }).join(', '); } else if (controls[key] && controls[key].type === 'BoundsControl') { return `Min: ${value[0]}, Max: ${value[1]}`; diff --git a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx b/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx index 3a12c2a..ca0d501 100644 --- a/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx +++ b/superset/assets/src/explore/components/controls/AdhocFilterControl.jsx @@ -16,12 +16,6 @@ import OnPasteSelect from '../../../components/OnPasteSelect'; import AdhocFilterOption from '../AdhocFilterOption'; import FilterDefinitionOption from '../FilterDefinitionOption'; -const legacyFilterShape = PropTypes.shape({ - col: PropTypes.string, - op: PropTypes.string, - val: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), -}); - const propTypes = { name: PropTypes.string, onChange: PropTypes.func, @@ -30,12 +24,8 @@ const propTypes = { columns: PropTypes.arrayOf(columnType), savedMetrics: PropTypes.arrayOf(savedMetricType), formData: PropTypes.shape({ - filters: PropTypes.arrayOf(legacyFilterShape), - having: PropTypes.string, - having_filters: PropTypes.arrayOf(legacyFilterShape), metric: PropTypes.oneOfType([PropTypes.string, adhocMetricType]), metrics: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, adhocMetricType])), - where: PropTypes.string, }), }; @@ -55,13 +45,15 @@ export default class AdhocFilterControl extends React.Component { constructor(props) { super(props); - this.coerceAdhocFilters = this.coerceAdhocFilters.bind(this); this.optionsForSelect = this.optionsForSelect.bind(this); this.onFilterEdit = this.onFilterEdit.bind(this); this.onChange = this.onChange.bind(this); this.getMetricExpression = this.getMetricExpression.bind(this); - const filters = this.coerceAdhocFilters(this.props.value, this.props.formData); + const filters = (this.props.value || []).map(filter => ( + isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter + )); + this.optionRenderer = VirtualizedRendererWrap(option => ( )); @@ -87,7 +79,11 @@ export default class AdhocFilterControl extends React.Component { this.setState({ options: this.optionsForSelect(nextProps) }); } if (this.props.value !== nextProps.value) { - this.setState({ values: this.coerceAdhocFilters(nextProps.value, nextProps.formData) }); + this.setState({ + values: (nextProps.value || []).map( + filter => (isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter + )), + }); } } @@ -147,62 +143,6 @@ export default class AdhocFilterControl extends React.Component { )).expression; } - coerceAdhocFilters(propsValues, formData) { - // this converts filters from the four legacy filter controls into adhoc filters in the case - // someone loads an old slice in the explore view - if (propsValues) { - return propsValues.map(filter => ( - isDictionaryForAdhocFilter(filter) ? new AdhocFilter(filter) : filter - )); - } - return [ - ...(formData.filters || []).map(filter => ( - new AdhocFilter({ - subject: filter.col, - operator: filter.op, - comparator: filter.val, - clause: CLAUSES.WHERE, - expressionType: EXPRESSION_TYPES.SIMPLE, - filterOptionName: this.generateConvertedFilterOptionName(), - }) - )), - ...(formData.having_filters || []).map(filter => ( - new AdhocFilter({ - subject: filter.col, - operator: filter.op, - comparator: filter.val, - clause: CLAUSES.HAVING, - expressionType: EXPRESSION_TYPES.SIMPLE, - filterOptionName: this.generateConvertedFilterOptionName(), - }) - )), - ...[ - formData.where ? - new AdhocFilter({ - sqlExpression: formData.where, - clause: CLAUSES.WHERE, - expressionType: EXPRESSION_TYPES.SQL, - filterOptionName: this.generateConvertedFilterOptionName(), - }) : - null, - ], - ...[ - formData.having ? - new AdhocFilter({ - sqlExpression: formData.having, - clause: CLAUSES.HAVING, - expressionType: EXPRESSION_TYPES.SQL, - filterOptionName: this.generateConvertedFilterOptionName(), - }) : - null, - ], - ].filter(option => option); - } - - generateConvertedFilterOptionName() { - return `form_filter_${Math.random().toString(36).substring(2, 15)}_${Math.random().toString(36).substring(2, 15)}`; - } - optionsForSelect(props) { const options = [ ...props.columns, diff --git a/superset/assets/src/explore/components/controls/Filter.jsx b/superset/assets/src/explore/components/controls/Filter.jsx deleted file mode 100644 index 539a413..0000000 --- a/superset/assets/src/explore/components/controls/Filter.jsx +++ /dev/null @@ -1,187 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import Select from 'react-select'; -import { Button, Row, Col } from 'react-bootstrap'; -import { t } from '../../../locales'; -import SelectControl from './SelectControl'; - -const operatorsArr = [ - { val: 'in', type: 'array', useSelect: true, multi: true }, - { val: 'not in', type: 'array', useSelect: true, multi: true }, - { val: '==', type: 'string', useSelect: true, multi: false, havingOnly: true }, - { val: '!=', type: 'string', useSelect: true, multi: false, havingOnly: true }, - { val: '>=', type: 'string', havingOnly: true }, - { val: '<=', type: 'string', havingOnly: true }, - { val: '>', type: 'string', havingOnly: true }, - { val: '<', type: 'string', havingOnly: true }, - { val: 'regex', type: 'string', datasourceTypes: ['druid'] }, - { val: 'LIKE', type: 'string', datasourceTypes: ['table'] }, - { val: 'IS NULL', type: null }, - { val: 'IS NOT NULL', type: null }, -]; -const operators = {}; -operatorsArr.forEach((op) => { - operators[op.val] = op; -}); - -const propTypes = { - changeFilter: PropTypes.func, - removeFilter: PropTypes.func, - filter: PropTypes.object.isRequired, - datasource: PropTypes.object, - having: PropTypes.bool, - valuesLoading: PropTypes.bool, - valueChoices: PropTypes.array, -}; - -const defaultProps = { - changeFilter: () => {}, - removeFilter: () => {}, - datasource: null, - having: false, - valuesLoading: false, - valueChoices: [], -}; - -export default class Filter extends React.Component { - - switchFilterValue(prevOp, nextOp) { - if (operators[prevOp].type !== operators[nextOp].type) { - // Switch from array to string or vice versa - const val = this.props.filter.val; - let newVal; - if (operators[nextOp].type === 'string') { - if (!val || !val.length) { - newVal = ''; - } else { - newVal = val[0]; - } - } else if (operators[nextOp].type === 'array') { - if (!val || !val.length) { - newVal = []; - } else { - newVal = [val]; - } - } - this.props.changeFilter(['val', 'op'], [newVal, nextOp]); - } else { - // No value type change - this.props.changeFilter('op', nextOp); - } - } - - changeText(event) { - this.props.changeFilter('val', event.target.value); - } - - changeSelect(value) { - this.props.changeFilter('val', value); - } - - changeColumn(event) { - this.props.changeFilter('col', event.value); - } - - changeOp(event) { - this.switchFilterValue(this.props.filter.op, event.value); - } - - removeFilter(filter) { - this.props.removeFilter(filter); - } - - renderFilterFormControl(filter) { - const operator = operators[filter.op]; - if (operator.type === null) { - // IS NULL or IS NOT NULL - return null; - } - if (operator.useSelect && !this.props.having) { - // TODO should use a simple Select, not a control here... - return ( - - ); - } - return ( - - ); - } - render() { - const datasource = this.props.datasource; - const filter = this.props.filter; - const opsChoices = operatorsArr - .filter((o) => { - if (this.props.having) { - return !!o.havingOnly; - } - return (!o.datasourceTypes || o.datasourceTypes.indexOf(datasource.type) >= 0); - }) - .map(o => ({ value: o.val, label: o.val })); - let colChoices; - if (datasource) { - if (this.props.having) { - colChoices = datasource.metrics_combo.map(c => ({ value: c[0], label: c[1] })); - } else { - colChoices = datasource.filterable_cols.map(c => ({ value: c[0], label: c[1] })); - } - } - return ( -
- - - - - - {this.renderFilterFormControl(filter)} - - - - - -
- ); - } -} - -Filter.propTypes = propTypes; -Filter.defaultProps = defaultProps; diff --git a/superset/assets/src/explore/components/controls/FilterControl.jsx b/superset/assets/src/explore/components/controls/FilterControl.jsx deleted file mode 100644 index 041dd6f..0000000 --- a/superset/assets/src/explore/components/controls/FilterControl.jsx +++ /dev/null @@ -1,155 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { Button, Row, Col } from 'react-bootstrap'; -import Filter from './Filter'; -import { t } from '../../../locales'; - -const $ = window.$ = require('jquery'); - -const propTypes = { - name: PropTypes.string, - onChange: PropTypes.func, - value: PropTypes.array, - datasource: PropTypes.object, -}; - -const defaultProps = { - onChange: () => {}, - value: [], -}; - -export default class FilterControl extends React.Component { - - constructor(props) { - super(props); - const initialFilters = props.value.map(() => ({ - valuesLoading: false, - valueChoices: [], - })); - this.state = { - filters: initialFilters, - activeRequest: null, - }; - } - - componentDidMount() { - this.state.filters.forEach((filter, index) => this.fetchFilterValues(index)); - } - - fetchFilterValues(index, column) { - const datasource = this.props.datasource; - const col = column || this.props.value[index].col; - const having = this.props.name === 'having_filters'; - if (col && this.props.datasource && this.props.datasource.filter_select && !having) { - this.setState((prevState) => { - const newStateFilters = Object.assign([], prevState.filters); - newStateFilters[index].valuesLoading = true; - return { filters: newStateFilters }; - }); - // if there is an outstanding request to fetch values, cancel it. - if (this.state.activeRequest) { - this.state.activeRequest.abort(); - } - this.setState({ - activeRequest: $.ajax({ - type: 'GET', - url: `/superset/filter/${datasource.type}/${datasource.id}/${col}/`, - success: (data) => { - this.setState((prevState) => { - const newStateFilters = Object.assign([], prevState.filters); - newStateFilters[index] = { valuesLoading: false, valueChoices: data }; - return { filters: newStateFilters, activeRequest: null }; - }); - }, - }), - }); - } - } - - addFilter() { - const newFilters = Object.assign([], this.props.value); - const col = this.props.datasource && this.props.datasource.filterable_cols.length > 0 ? - this.props.datasource.filterable_cols[0][0] : - null; - newFilters.push({ - col, - op: 'in', - val: this.props.datasource.filter_select ? [] : '', - }); - this.props.onChange(newFilters); - const nextIndex = this.state.filters.length; - this.setState((prevState) => { - const newStateFilters = Object.assign([], prevState.filters); - newStateFilters.push({ valuesLoading: false, valueChoices: [] }); - return { filters: newStateFilters }; - }); - this.fetchFilterValues(nextIndex, col); - } - - changeFilter(index, control, value) { - const newFilters = Object.assign([], this.props.value); - const modifiedFilter = Object.assign({}, newFilters[index]); - if (typeof control === 'string') { - modifiedFilter[control] = value; - } else { - control.forEach((c, i) => { - modifiedFilter[c] = value[i]; - }); - } - // Clear selected values and refresh upon column change - if (control === 'col') { - if (modifiedFilter.val.constructor === Array) { - modifiedFilter.val = []; - } else if (typeof modifiedFilter.val === 'string') { - modifiedFilter.val = ''; - } - this.fetchFilterValues(index, value); - } - newFilters.splice(index, 1, modifiedFilter); - this.props.onChange(newFilters); - } - - removeFilter(index) { - this.props.onChange(this.props.value.filter((f, i) => i !== index)); - this.setState((prevState) => { - const newStateFilters = Object.assign([], prevState.filters); - newStateFilters.splice(index, 1); - return { filters: newStateFilters }; - }); - } - - render() { - const filters = this.props.value.map((filter, i) => ( -
- -
- )); - return ( -
- {filters} - - - - - -
- ); - } -} - -FilterControl.propTypes = propTypes; -FilterControl.defaultProps = defaultProps; diff --git a/superset/assets/src/explore/components/controls/index.js b/superset/assets/src/explore/components/controls/index.js index 8199127..4a2df42 100644 --- a/superset/assets/src/explore/components/controls/index.js +++ b/superset/assets/src/explore/components/controls/index.js @@ -6,7 +6,6 @@ import ColorPickerControl from './ColorPickerControl'; import ColorSchemeControl from './ColorSchemeControl'; import DatasourceControl from './DatasourceControl'; import DateFilterControl from './DateFilterControl'; -import FilterControl from './FilterControl'; import FixedOrMetricControl from './FixedOrMetricControl'; import HiddenControl from './HiddenControl'; import SelectAsyncControl from './SelectAsyncControl'; @@ -29,7 +28,6 @@ const controlMap = { ColorSchemeControl, DatasourceControl, DateFilterControl, - FilterControl, FixedOrMetricControl, HiddenControl, SelectAsyncControl, diff --git a/superset/assets/src/explore/controls.jsx b/superset/assets/src/explore/controls.jsx index b2382c1..0281fe1 100644 --- a/superset/assets/src/explore/controls.jsx +++ b/superset/assets/src/explore/controls.jsx @@ -1132,34 +1132,6 @@ export const controls = { default: '', }, - where: { - type: 'TextAreaControl', - label: t('Custom WHERE clause'), - default: '', - language: 'sql', - minLines: 2, - maxLines: 10, - offerEditInModal: false, - description: t('The text in this box gets included in your query\'s WHERE ' + - 'clause, as an AND to other criteria. You can include ' + - 'complex expression, parenthesis and anything else ' + - 'supported by the backend it is directed towards.'), - }, - - having: { - type: 'TextAreaControl', - label: t('Custom HAVING clause'), - default: '', - language: 'sql', - minLines: 2, - maxLines: 10, - offerEditInModal: false, - description: t('The text in this box gets included in your query\'s HAVING ' + - 'clause, as an AND to other criteria. You can include ' + - 'complex expression, parenthesis and anything else ' + - 'supported by the backend it is directed towards.'), - }, - compare_lag: { type: 'TextControl', label: t('Comparison Period Lag'), @@ -1822,16 +1794,6 @@ export const controls = { description: t('Labels for the marker lines'), }, - filters: { - type: 'FilterControl', - label: '', - default: [], - description: '', - mapStateToProps: state => ({ - datasource: state.datasource, - }), - }, - annotation_layers: { type: 'AnnotationLayerControl', label: '', @@ -1854,18 +1816,6 @@ export const controls = { provideFormDataToProps: true, }, - having_filters: { - type: 'FilterControl', - label: '', - default: [], - description: '', - mapStateToProps: state => ({ - choices: (state.datasource) ? state.datasource.metrics_combo - .concat(state.datasource.filterable_cols) : [], - datasource: state.datasource, - }), - }, - slice_id: { type: 'HiddenControl', label: t('Chart ID'), diff --git a/superset/assets/src/explore/store.js b/superset/assets/src/explore/store.js index 32c132f..48a24df 100644 --- a/superset/assets/src/explore/store.js +++ b/superset/assets/src/explore/store.js @@ -68,14 +68,6 @@ export function getControlsState(state, form_data) { delete formData[k]; } } - // Removing invalid filters that point to a now inexisting column - if (control.type === 'FilterControl' && control.choices) { - if (!formData[k]) { - formData[k] = []; - } - const choiceValues = control.choices.map(c => c[0]); - formData[k] = formData[k].filter(flt => choiceValues.indexOf(flt.col) >= 0); - } if (typeof control.default === 'function') { control.default = control.default(control); diff --git a/superset/assets/src/explore/visTypes.js b/superset/assets/src/explore/visTypes.js index f771c38..b0037ec 100644 --- a/superset/assets/src/explore/visTypes.js +++ b/superset/assets/src/explore/visTypes.js @@ -40,14 +40,6 @@ export const sections = { ['since', 'until'], ], }, - sqlClause: { - label: t('SQL'), - controlSetRows: [ - ['where'], - ['having'], - ], - description: t('This section exposes ways to include snippets of SQL in your query'), - }, annotations: { label: t('Annotations and Layers'), expanded: true, @@ -80,20 +72,6 @@ export const sections = { ], }, ], - filters: [ - { - label: t('Filters'), - expanded: true, - controlSetRows: [['filters']], - }, - { - label: t('Result Filters'), - expanded: true, - description: t('The filters to apply after post-aggregation.' + - 'Leave the value control empty to filter empty strings or nulls'), - controlSetRows: [['having_filters']], - }, - ], }; const timeGrainSqlaAnimationOverrides = { @@ -263,6 +241,13 @@ export const visTypes = { ['line_charts_2', 'y_axis_2_format'], ], }, + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['adhoc_filters'], + ], + }, sections.annotations, ], controlOverrides: { @@ -279,8 +264,6 @@ export const visTypes = { }, }, sectionOverrides: { - sqlClause: [], - filters: [[]], datasourceAndVizType: { label: t('Chart Type'), controlSetRows: [ @@ -310,7 +293,9 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ - ['metric', 'freq'], + ['metric'], + ['adhoc_filters'], + ['freq'], ], }, { @@ -373,6 +358,13 @@ export const visTypes = { ['metric_2', 'y_axis_2_format'], ], }, + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['adhoc_filters'], + ], + }, sections.annotations, ], controlOverrides: { @@ -489,6 +481,13 @@ export const visTypes = { ['deck_slices', null], ], }, + { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['adhoc_filters'], + ], + }, ], }, @@ -502,6 +501,7 @@ export const visTypes = { controlSetRows: [ ['spatial', 'size'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -540,6 +540,7 @@ export const visTypes = { controlSetRows: [ ['spatial', 'size'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -579,6 +580,7 @@ export const visTypes = { controlSetRows: [ ['line_column', 'line_type'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -612,6 +614,7 @@ export const visTypes = { controlSetRows: [ ['spatial', 'size'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -656,6 +659,7 @@ export const visTypes = { expanded: true, controlSetRows: [ ['geojson', 'row_limit'], + ['adhoc_filters'], ], }, { @@ -696,6 +700,7 @@ export const visTypes = { controlSetRows: [ ['line_column', 'line_type'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -736,6 +741,7 @@ export const visTypes = { controlSetRows: [ ['start_spatial', 'end_spatial'], ['row_limit', null], + ['adhoc_filters'], ], }, { @@ -784,6 +790,7 @@ export const visTypes = { expanded: true, controlSetRows: [ ['spatial', 'row_limit'], + ['adhoc_filters'], ], }, { @@ -902,6 +909,13 @@ export const visTypes = { ], }, { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['adhoc_filters'], + ], + }, + { label: t('Options'), expanded: true, controlSetRows: [ @@ -929,7 +943,9 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ - ['groupby', 'metrics'], + ['metrics'], + ['adhoc_filters'], + ['groupby'], ['limit'], ['column_collection'], ['url'], @@ -969,8 +985,10 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ - ['groupby', 'columns'], ['metrics'], + ['adhoc_filters'], + ['groupby'], + ['columns'], ['row_limit', null], ], }, @@ -1017,7 +1035,9 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ - ['series', 'metric'], + ['metric'], + ['adhoc_filters'], + ['series'], ['row_limit', null], ], }, @@ -1040,6 +1060,7 @@ export const visTypes = { expanded: true, controlSetRows: [ ['metrics'], + ['adhoc_filters'], ['groupby'], ], }, @@ -1070,6 +1091,7 @@ export const visTypes = { controlSetRows: [ ['domain_granularity', 'subdomain_granularity'], ['metrics'], + ['adhoc_filters'], ], }, { @@ -1106,7 +1128,9 @@ export const visTypes = { expanded: true, controlSetRows: [ ['metrics'], - ['groupby', 'limit'], + ['adhoc_filters'], + ['groupby'], + ['limit'], ], }, { @@ -1128,8 +1152,11 @@ export const visTypes = { expanded: true, controlSetRows: [ ['series', 'entity'], - ['x', 'y'], - ['size', 'max_bubble_size'], + ['x'], + ['y'], + ['adhoc_filters'], + ['size'], + ['max_bubble_size'], ['limit', null], ], }, @@ -1179,6 +1206,7 @@ export const visTypes = { expanded: true, controlSetRows: [ ['metric'], + ['adhoc_filters'], ], }, { @@ -1256,6 +1284,7 @@ export const visTypes = { expanded: true, controlSetRows: [ ['all_columns_x'], + ['adhoc_filters'], ['row_limit'], ['groupby'], ], @@ -1298,7 +1327,9 @@ export const visTypes = { expanded: true, controlSetRows: [ ['groupby'], - ['metric', 'secondary_metric'], + ['metric'], + ['secondary_metric'], + ['adhoc_filters'], ['row_limit'], ], }, @@ -1338,6 +1369,7 @@ export const visTypes = { controlSetRows: [ ['groupby'], ['metric'], + ['adhoc_filters'], ['row_limit'], ], }, @@ -1366,6 +1398,7 @@ export const visTypes = { controlSetRows: [ ['groupby'], ['metric'], + ['adhoc_filters'], ['row_limit'], ], }, @@ -1391,8 +1424,11 @@ export const visTypes = { label: t('Query'), expanded: true, controlSetRows: [ - ['groupby', 'columns'], - ['metric', 'row_limit'], + ['groupby'], + ['columns'], + ['metric'], + ['adhoc_filters'], + ['row_limit'], ], }, { @@ -1432,6 +1468,7 @@ export const visTypes = { controlSetRows: [ ['entity'], ['metric'], + ['adhoc_filters'], ], }, { @@ -1467,6 +1504,7 @@ export const visTypes = { ['entity'], ['country_fieldtype'], ['metric'], + ['adhoc_filters'], ], }, { @@ -1503,6 +1541,7 @@ export const visTypes = { controlSetRows: [ ['groupby'], ['metric'], + ['adhoc_filters'], ['date_filter', 'instant_filtering'], ['show_sqla_time_granularity', 'show_sqla_time_column'], ['show_druid_time_granularity', 'show_druid_time_origin'], @@ -1544,6 +1583,7 @@ export const visTypes = { ['series'], ['metrics'], ['secondary_metric'], + ['adhoc_filters'], ['limit'], ], }, @@ -1564,7 +1604,9 @@ export const visTypes = { expanded: true, controlSetRows: [ ['all_columns_x', 'all_columns_y'], - ['metric', 'row_limit'], + ['metric'], + ['adhoc_filters'], + ['row_limit'], ], }, { @@ -1627,6 +1669,7 @@ export const visTypes = { ['all_columns_x', 'all_columns_y'], ['clustering_radius'], ['row_limit'], + ['adhoc_filters'], ['groupby'], ], }, @@ -1702,6 +1745,13 @@ export const visTypes = { ], }, { + label: t('Query'), + expanded: true, + controlSetRows: [ + ['adhoc_filters'], + ], + }, + { label: t('Additional meta data'), controlSetRows: [ ['all_columns'], @@ -1799,12 +1849,6 @@ export const visTypes = { export default visTypes; -function adhocFilterEnabled(viz) { - return viz.controlPanelSections.find(( - section => section.controlSetRows.find(row => row.find(control => control === 'adhoc_filters')) - )); -} - export function sectionsToRender(vizType, datasourceType) { const viz = visTypes[vizType]; @@ -1826,7 +1870,5 @@ export function sectionsToRender(vizType, datasourceType) { sectionsCopy.datasourceAndVizType, datasourceType === 'table' ? sectionsCopy.sqlaTimeSeries : sectionsCopy.druidTimeSeries, viz.controlPanelSections, - !adhocFilterEnabled(viz) && (datasourceType === 'table' ? sectionsCopy.sqlClause : []), - !adhocFilterEnabled(viz) && (datasourceType === 'table' ? sectionsCopy.filters[0] : sectionsCopy.filters), ).filter(section => section); } diff --git a/superset/migrations/versions/bddc498dd179_adhoc_filters.py b/superset/migrations/versions/bddc498dd179_adhoc_filters.py new file mode 100644 index 0000000..55503f0 --- /dev/null +++ b/superset/migrations/versions/bddc498dd179_adhoc_filters.py @@ -0,0 +1,97 @@ +"""adhoc filters + +Revision ID: bddc498dd179 +Revises: afb7730f6a9c +Create Date: 2018-06-13 14:54:47.086507 + +""" + +# revision identifiers, used by Alembic. +revision = 'bddc498dd179' +down_revision = '80a67c5192fa' + + +from collections import defaultdict +import json +import uuid + +from alembic import op +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy import Column, Integer, Text + +from superset import db +from superset import utils + + +Base = declarative_base() + + +class Slice(Base): + __tablename__ = 'slices' + + id = Column(Integer, primary_key=True) + params = Column(Text) + + +def upgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + mapping = {'having': 'having_filters', 'where': 'filters'} + + for slc in session.query(Slice).all(): + try: + params = json.loads(slc.params) + + if not 'adhoc_filters' in params: + params['adhoc_filters'] = [] + + for clause, filters in mapping.items(): + if clause in params and params[clause] != '': + params['adhoc_filters'].append({ + 'clause': clause.upper(), + 'expressionType': 'SQL', + 'filterOptionName': str(uuid.uuid4()), + 'sqlExpression': params[clause], + }) + + if filters in params: + for filt in params[filters]: + params['adhoc_filters'].append({ + 'clause': clause.upper(), + 'comparator': filt['val'], + 'expressionType': 'SIMPLE', + 'filterOptionName': str(uuid.uuid4()), + 'operator': filt['op'], + 'subject': filt['col'], + }) + + for key in ('filters', 'having', 'having_filters', 'where'): + if key in params: + del params[key] + + slc.params = json.dumps(params, sort_keys=True) + except Exception: + pass + + session.commit() + session.close() + + +def downgrade(): + bind = op.get_bind() + session = db.Session(bind=bind) + + for slc in session.query(Slice).all(): + try: + params = json.loads(slc.params) + utils.split_adhoc_filters_into_base_filters(params) + + if 'adhoc_filters' in params: + del params['adhoc_filters'] + + slc.params = json.dumps(params, sort_keys=True) + except Exception: + pass + + session.commit() + session.close() diff --git a/superset/translations/de/LC_MESSAGES/messages.po b/superset/translations/de/LC_MESSAGES/messages.po index 7db79cd..59077e2 100644 --- a/superset/translations/de/LC_MESSAGES/messages.po +++ b/superset/translations/de/LC_MESSAGES/messages.po @@ -1193,7 +1193,6 @@ msgstr "" msgid "Select operator" msgstr "" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:138 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "" diff --git a/superset/translations/en/LC_MESSAGES/messages.po b/superset/translations/en/LC_MESSAGES/messages.po index 3d5e245..a861350 100644 --- a/superset/translations/en/LC_MESSAGES/messages.po +++ b/superset/translations/en/LC_MESSAGES/messages.po @@ -3815,7 +3815,6 @@ msgstr "" msgid "Select operator" msgstr "" -#: superset/assets/src/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "" diff --git a/superset/translations/es/LC_MESSAGES/messages.po b/superset/translations/es/LC_MESSAGES/messages.po index 4742f76..1dbd464 100644 --- a/superset/translations/es/LC_MESSAGES/messages.po +++ b/superset/translations/es/LC_MESSAGES/messages.po @@ -1250,7 +1250,6 @@ msgstr "Selecciona la columna" msgid "Select operator" msgstr "Selecciona el operador" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:138 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "Añadir Filtro" diff --git a/superset/translations/fr/LC_MESSAGES/messages.po b/superset/translations/fr/LC_MESSAGES/messages.po index f3914a4..16245c3 100644 --- a/superset/translations/fr/LC_MESSAGES/messages.po +++ b/superset/translations/fr/LC_MESSAGES/messages.po @@ -3819,7 +3819,6 @@ msgstr "" msgid "Select operator" msgstr "" -#: superset/assets/src/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "Ajouter un filtre" diff --git a/superset/translations/it/LC_MESSAGES/messages.po b/superset/translations/it/LC_MESSAGES/messages.po index 5ef5b4b..f383e14 100644 --- a/superset/translations/it/LC_MESSAGES/messages.po +++ b/superset/translations/it/LC_MESSAGES/messages.po @@ -1598,7 +1598,6 @@ msgstr "Seleziona una colonna" msgid "Select operator" msgstr "Seleziona operatore" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "Aggiungi filtro" diff --git a/superset/translations/ja/LC_MESSAGES/messages.po b/superset/translations/ja/LC_MESSAGES/messages.po index 5f6b714..df16185 100644 --- a/superset/translations/ja/LC_MESSAGES/messages.po +++ b/superset/translations/ja/LC_MESSAGES/messages.po @@ -1202,7 +1202,6 @@ msgstr "列を選択" msgid "Select operator" msgstr "オペレータを選択" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:138 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "フィルターを追加" diff --git a/superset/translations/messages.pot b/superset/translations/messages.pot index 23d2cb4..09c3e36 100644 --- a/superset/translations/messages.pot +++ b/superset/translations/messages.pot @@ -3814,7 +3814,6 @@ msgstr "" msgid "Select operator" msgstr "" -#: superset/assets/src/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "" diff --git a/superset/translations/pt_BR/LC_MESSAGES/messages.po b/superset/translations/pt_BR/LC_MESSAGES/messages.po index b2a5b34..8710021 100644 --- a/superset/translations/pt_BR/LC_MESSAGES/messages.po +++ b/superset/translations/pt_BR/LC_MESSAGES/messages.po @@ -1256,7 +1256,6 @@ msgstr "Selecione a coluna" msgid "Select operator" msgstr "Selecione o operador" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:138 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "Adicionar filtro" diff --git a/superset/translations/ru/LC_MESSAGES/messages.po b/superset/translations/ru/LC_MESSAGES/messages.po index 79e5713..5ea2cc1 100644 --- a/superset/translations/ru/LC_MESSAGES/messages.po +++ b/superset/translations/ru/LC_MESSAGES/messages.po @@ -1599,7 +1599,6 @@ msgstr "Выбрать столбец" msgid "Select operator" msgstr "Выбрать оператор" -#: superset/assets/javascripts/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "Добавить фильтр" diff --git a/superset/translations/zh/LC_MESSAGES/messages.po b/superset/translations/zh/LC_MESSAGES/messages.po index 0a9cc2f..4cd37c9 100644 --- a/superset/translations/zh/LC_MESSAGES/messages.po +++ b/superset/translations/zh/LC_MESSAGES/messages.po @@ -3820,7 +3820,6 @@ msgstr "选择列" msgid "Select operator" msgstr "选择运算符" -#: superset/assets/src/explore/components/controls/FilterControl.jsx:145 #: superset/templates/appbuilder/general/widgets/search.html:6 msgid "Add Filter" msgstr "增加过滤条件" diff --git a/superset/utils.py b/superset/utils.py index 08ce0d2..eec2530 100644 --- a/superset/utils.py +++ b/superset/utils.py @@ -881,4 +881,3 @@ def split_adhoc_filters_into_base_filters(fd): fd['having'] = ' AND '.join(['({})'.format(sql) for sql in sql_having_filters]) fd['having_filters'] = simple_having_filters fd['filters'] = simple_where_filters - del fd['adhoc_filters']