From fbf2189713dbf9a8827583f9f4aa5b66603f75a2 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Fri, 20 Mar 2020 12:29:00 -0700 Subject: [PATCH 01/12] filter owners select by text input --- superset-frontend/package.json | 2 +- .../dashboard/components/PropertiesModal.jsx | 123 +++++++++--------- .../explore/components/PropertiesModal.tsx | 51 ++++---- 3 files changed, 86 insertions(+), 90 deletions(-) diff --git a/superset-frontend/package.json b/superset-frontend/package.json index 01597d607d628..a485711b3a20b 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -92,6 +92,7 @@ "@superset-ui/translation": "^0.12.8", "@types/classnames": "^2.2.9", "@types/react-json-tree": "^0.6.11", + "@types/react-select": "^1.2.1", "@vx/responsive": "^0.0.195", "abortcontroller-polyfill": "^1.1.9", "aphrodite": "^2.3.1", @@ -177,7 +178,6 @@ "@types/react": "^16.9.23", "@types/react-dom": "^16.9.5", "@types/react-redux": "^7.1.7", - "@types/react-select": "^3.0.10", "@types/react-table": "^7.0.2", "@types/react-ultimate-pagination": "^1.2.0", "@types/yargs": "12 - 15", diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index f266465b8c576..b5969b7c97afd 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { Row, Col, Button, Modal, FormControl } from 'react-bootstrap'; import Dialog from 'react-bootstrap-dialog'; -import Select from 'react-select'; +import { Async as SelectAsync } from 'react-select'; import AceEditor from 'react-ace'; import { t } from '@superset-ui/translation'; import { SupersetClient } from '@superset-ui/connection'; @@ -55,7 +55,6 @@ class PropertiesModal extends React.PureComponent { json_metadata: '', }, isDashboardLoaded: false, - ownerOptions: null, isAdvancedOpen: false, }; this.onChange = this.onChange.bind(this); @@ -63,10 +62,11 @@ class PropertiesModal extends React.PureComponent { this.onOwnersChange = this.onOwnersChange.bind(this); this.save = this.save.bind(this); this.toggleAdvanced = this.toggleAdvanced.bind(this); + this.loadOwnerOptions = this.loadOwnerOptions.bind(this); + this.handleErrorResponse = this.handleErrorResponse.bind(this); } componentDidMount() { - this.fetchOwnerOptions(); this.fetchDashboardDetails(); } @@ -90,41 +90,41 @@ class PropertiesModal extends React.PureComponent { // datamodel, the dashboard could probably just be passed as a prop. SupersetClient.get({ endpoint: `/api/v1/dashboard/${this.props.dashboardId}`, - }) - .then(response => { - const dashboard = response.json.result; - this.setState(state => ({ - isDashboardLoaded: true, - values: { - ...state.values, - dashboard_title: dashboard.dashboard_title || '', - slug: dashboard.slug || '', - json_metadata: dashboard.json_metadata || '', - }, - })); - const initialSelectedValues = dashboard.owners.map(owner => ({ - value: owner.id, - label: owner.username, - })); - this.onOwnersChange(initialSelectedValues); - }) - .catch(err => console.error(err)); + }).then(response => { + const dashboard = response.json.result; + this.setState(state => ({ + isDashboardLoaded: true, + values: { + ...state.values, + dashboard_title: dashboard.dashboard_title || '', + slug: dashboard.slug || '', + json_metadata: dashboard.json_metadata || '', + }, + })); + const initialSelectedOwners = dashboard.owners.map(owner => ({ + value: owner.id, + label: owner.username, + })); + this.onOwnersChange(initialSelectedOwners); + }, this.handleErrorResponse); } - fetchOwnerOptions() { - SupersetClient.get({ - endpoint: `/api/v1/dashboard/related/owners`, - }) - .then(response => { + loadOwnerOptions(input = '') { + return SupersetClient.get({ + endpoint: `/api/v1/dashboard/related/owners?filter=${input}`, + }).then( + response => { const options = response.json.result.map(item => ({ value: item.value, label: item.text, })); - this.setState({ - ownerOptions: options, - }); - }) - .catch(err => console.error(err)); + return { options }; + }, + badResponse => { + this.handleErrorResponse(badResponse); + return { options: [] }; + }, + ); } updateFormState(name, value) { @@ -142,6 +142,17 @@ class PropertiesModal extends React.PureComponent { })); } + async handleErrorResponse(response) { + const { error, statusText } = await getClientErrorObject(response); + this.dialog.show({ + title: 'Error', + bsSize: 'medium', + bsStyle: 'danger', + actions: [Dialog.DefaultAction('Ok', () => {}, 'btn-danger')], + body: error || statusText || t('An error has occurred'), + }); + } + save(e) { e.preventDefault(); e.stopPropagation(); @@ -157,38 +168,21 @@ class PropertiesModal extends React.PureComponent { json_metadata: values.json_metadata || null, owners, }), - }) - .then(({ json }) => { - this.props.addSuccessToast(t('The dashboard has been saved')); - this.props.onDashboardSave({ - id: this.props.dashboardId, - title: json.result.dashboard_title, - slug: json.result.slug, - jsonMetadata: json.result.json_metadata, - ownerIds: json.result.owners, - }); - this.props.onHide(); - }) - .catch(response => - getClientErrorObject(response).then(({ error, statusText }) => { - this.dialog.show({ - title: 'Error', - bsSize: 'medium', - bsStyle: 'danger', - actions: [Dialog.DefaultAction('Ok', () => {}, 'btn-danger')], - body: error || statusText || t('An error has occurred'), - }); - }), - ); + }).then(({ json }) => { + this.props.addSuccessToast(t('The dashboard has been saved')); + this.props.onDashboardSave({ + id: this.props.dashboardId, + title: json.result.dashboard_title, + slug: json.result.slug, + jsonMetadata: json.result.json_metadata, + ownerIds: json.result.owners, + }); + this.props.onHide(); + }, this.handleErrorResponse); } render() { - const { - ownerOptions, - values, - isDashboardLoaded, - isAdvancedOpen, - } = this.state; + const { values, isDashboardLoaded, isAdvancedOpen } = this.state; return (
@@ -242,14 +236,13 @@ class PropertiesModal extends React.PureComponent { -

{t('A list of users who can alter the chart')} From 8ce7ffa8e182426996cf66844d29bf7897d7e69a Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Fri, 20 Mar 2020 17:17:12 -0700 Subject: [PATCH 02/12] use rison --- superset-frontend/package-lock.json | 290 +++++++++--------- superset-frontend/package.json | 2 + .../dashboard/components/PropertiesModal.jsx | 4 +- .../explore/components/PropertiesModal.tsx | 9 +- 4 files changed, 155 insertions(+), 150 deletions(-) diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index 2c64cf241535c..81cf62ae78e71 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -8795,14 +8795,11 @@ } }, "@types/react-select": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-3.0.10.tgz", - "integrity": "sha512-oUHXqvbkRhC07q5JjeY6hE+NUqgUM6CyaRXEKYPvMCBqUOuLnYltyhiNx6Jpb+iFpYtNHSQtF4dNJfMdMooKoQ==", - "dev": true, + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-1.3.4.tgz", + "integrity": "sha512-0BwjswNzKBszG5O4xq72W54NrrbmOZvJfaM/Dwru3F6DhvFO9nihMP1IRzXSOJ1qGRCS3VCu9FnBYJ+25lSldw==", "requires": { - "@types/react": "*", - "@types/react-dom": "*", - "@types/react-transition-group": "*" + "@types/react": "*" } }, "@types/react-table": { @@ -8814,15 +8811,6 @@ "@types/react": "*" } }, - "@types/react-transition-group": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.4.tgz", - "integrity": "sha512-8DMUaDqh0S70TjkqU0DxOu80tFUiiaS9rxkWip/nb7gtvAsbqOXm02UCmR8zdcjWujgeYPiPNTVpVpKzUDotwA==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react-ultimate-pagination": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/react-ultimate-pagination/-/react-ultimate-pagination-1.2.0.tgz", @@ -8849,6 +8837,11 @@ "@types/react": "*" } }, + "@types/rison": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/rison/-/rison-0.0.6.tgz", + "integrity": "sha512-mE3eRK0fpTN/GnNBOIg2tGq2cFhchQXF6fCbrLxus75TgnoOECbdHikr948FGO/UAml7/ZhLMa5FbGkF5PKvmw==" + }, "@types/shortid": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", @@ -11512,28 +11505,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -11544,14 +11537,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -11562,42 +11555,42 @@ }, "chownr": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "optional": true, @@ -11607,28 +11600,28 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -11638,14 +11631,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -11662,7 +11655,7 @@ }, "glob": { "version": "7.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "optional": true, @@ -11677,14 +11670,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": false, + "resolved": "", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -11694,7 +11687,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -11704,7 +11697,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -11715,21 +11708,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -11739,14 +11732,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -11756,14 +11749,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "optional": true, @@ -11774,7 +11767,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": false, + "resolved": "", "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "optional": true, @@ -11784,7 +11777,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -11794,14 +11787,14 @@ }, "ms": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true, "optional": true }, "needle": { "version": "2.3.0", - "resolved": false, + "resolved": "", "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", "dev": true, "optional": true, @@ -11813,7 +11806,7 @@ }, "node-pre-gyp": { "version": "0.12.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", "dev": true, "optional": true, @@ -11832,7 +11825,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -11843,14 +11836,14 @@ }, "npm-bundled": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", "dev": true, "optional": true, @@ -11861,7 +11854,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -11874,21 +11867,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -11898,21 +11891,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -11923,21 +11916,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -11959,7 +11952,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -11975,7 +11968,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": false, + "resolved": "", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "optional": true, @@ -11985,49 +11978,49 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.7.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -12039,7 +12032,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -12049,7 +12042,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -12059,14 +12052,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.8", - "resolved": false, + "resolved": "", "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, @@ -12082,14 +12075,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -12099,14 +12092,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true, "optional": true @@ -16437,28 +16430,28 @@ "dependencies": { "abbrev": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true, "optional": true }, "aproba": { "version": "1.2.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "dev": true, "optional": true, @@ -16469,14 +16462,14 @@ }, "balanced-match": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true, "optional": true }, "brace-expansion": { "version": "1.1.11", - "resolved": false, + "resolved": "", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "optional": true, @@ -16487,42 +16480,42 @@ }, "chownr": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true, "optional": true }, "concat-map": { "version": "0.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true, "optional": true }, "console-control-strings": { "version": "1.1.0", - "resolved": false, + "resolved": "", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true, "optional": true }, "core-util-is": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true, "optional": true }, "debug": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "dev": true, "optional": true, @@ -16532,28 +16525,28 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "optional": true }, "delegates": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", - "resolved": false, + "resolved": "", "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", "dev": true, "optional": true, @@ -16563,14 +16556,14 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true, "optional": true }, "gauge": { "version": "2.7.4", - "resolved": false, + "resolved": "", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "dev": true, "optional": true, @@ -16587,7 +16580,7 @@ }, "glob": { "version": "7.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "optional": true, @@ -16602,14 +16595,14 @@ }, "has-unicode": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.24", - "resolved": false, + "resolved": "", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "optional": true, @@ -16619,7 +16612,7 @@ }, "ignore-walk": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", "dev": true, "optional": true, @@ -16629,7 +16622,7 @@ }, "inflight": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "optional": true, @@ -16640,21 +16633,21 @@ }, "inherits": { "version": "2.0.3", - "resolved": false, + "resolved": "", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true, "optional": true }, "ini": { "version": "1.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "optional": true, @@ -16664,14 +16657,14 @@ }, "isarray": { "version": "1.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", - "resolved": false, + "resolved": "", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "optional": true, @@ -16681,14 +16674,14 @@ }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true, "optional": true }, "minipass": { "version": "2.3.5", - "resolved": false, + "resolved": "", "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", "dev": true, "optional": true, @@ -16699,7 +16692,7 @@ }, "minizlib": { "version": "1.2.1", - "resolved": false, + "resolved": "", "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", "dev": true, "optional": true, @@ -16709,7 +16702,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, @@ -16719,14 +16712,14 @@ }, "ms": { "version": "2.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true, "optional": true }, "needle": { "version": "2.3.0", - "resolved": false, + "resolved": "", "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==", "dev": true, "optional": true, @@ -16738,7 +16731,7 @@ }, "node-pre-gyp": { "version": "0.12.0", - "resolved": false, + "resolved": "", "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==", "dev": true, "optional": true, @@ -16757,7 +16750,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "dev": true, "optional": true, @@ -16768,14 +16761,14 @@ }, "npm-bundled": { "version": "1.0.6", - "resolved": false, + "resolved": "", "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==", "dev": true, "optional": true }, "npm-packlist": { "version": "1.4.1", - "resolved": false, + "resolved": "", "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==", "dev": true, "optional": true, @@ -16786,7 +16779,7 @@ }, "npmlog": { "version": "4.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "dev": true, "optional": true, @@ -16799,21 +16792,21 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true, "optional": true }, "object-assign": { "version": "4.1.1", - "resolved": false, + "resolved": "", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true, "optional": true }, "once": { "version": "1.4.0", - "resolved": false, + "resolved": "", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "optional": true, @@ -16823,21 +16816,21 @@ }, "os-homedir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true, "optional": true }, "osenv": { "version": "0.1.5", - "resolved": false, + "resolved": "", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "dev": true, "optional": true, @@ -16848,21 +16841,21 @@ }, "path-is-absolute": { "version": "1.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true, "optional": true }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "optional": true, @@ -16884,7 +16877,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": false, + "resolved": "", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "optional": true, @@ -16900,7 +16893,7 @@ }, "rimraf": { "version": "2.6.3", - "resolved": false, + "resolved": "", "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "optional": true, @@ -16910,49 +16903,49 @@ }, "safe-buffer": { "version": "5.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "optional": true }, "safer-buffer": { "version": "2.1.2", - "resolved": false, + "resolved": "", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "optional": true }, "sax": { "version": "1.2.4", - "resolved": false, + "resolved": "", "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, "optional": true }, "semver": { "version": "5.7.0", - "resolved": false, + "resolved": "", "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true, "optional": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "optional": true, @@ -16964,7 +16957,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": false, + "resolved": "", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "optional": true, @@ -16974,7 +16967,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "optional": true, @@ -16984,14 +16977,14 @@ }, "strip-json-comments": { "version": "2.0.1", - "resolved": false, + "resolved": "", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true, "optional": true }, "tar": { "version": "4.4.8", - "resolved": false, + "resolved": "", "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, @@ -17007,14 +17000,14 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true, "optional": true }, "wide-align": { "version": "1.1.3", - "resolved": false, + "resolved": "", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "dev": true, "optional": true, @@ -17024,14 +17017,14 @@ }, "wrappy": { "version": "1.0.2", - "resolved": false, + "resolved": "", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true, "optional": true }, "yallist": { "version": "3.0.3", - "resolved": false, + "resolved": "", "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", "dev": true, "optional": true @@ -31670,6 +31663,11 @@ "inherits": "^2.0.1" } }, + "rison": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/rison/-/rison-0.1.1.tgz", + "integrity": "sha1-TcwFV7JBr/YOdheOd5ITVxPzMSA=" + }, "rst-selector-parser": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz", diff --git a/superset-frontend/package.json b/superset-frontend/package.json index a485711b3a20b..9602f20f24892 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -93,6 +93,7 @@ "@types/classnames": "^2.2.9", "@types/react-json-tree": "^0.6.11", "@types/react-select": "^1.2.1", + "@types/rison": "0.0.6", "@vx/responsive": "^0.0.195", "abortcontroller-polyfill": "^1.1.9", "aphrodite": "^2.3.1", @@ -157,6 +158,7 @@ "redux-thunk": "^2.1.0", "redux-undo": "^1.0.0-beta9-9-7", "regenerator-runtime": "^0.13.3", + "rison": "^0.1.1", "shortid": "^2.2.6", "urijs": "^1.18.10", "use-query-params": "^0.4.5" diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index b5969b7c97afd..506fcd1475308 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -22,6 +22,7 @@ import { Row, Col, Button, Modal, FormControl } from 'react-bootstrap'; import Dialog from 'react-bootstrap-dialog'; import { Async as SelectAsync } from 'react-select'; import AceEditor from 'react-ace'; +import rison from 'rison'; import { t } from '@superset-ui/translation'; import { SupersetClient } from '@superset-ui/connection'; import '../stylesheets/buttons.less'; @@ -110,8 +111,9 @@ class PropertiesModal extends React.PureComponent { } loadOwnerOptions(input = '') { + const query = rison.encode({ filter: input }); return SupersetClient.get({ - endpoint: `/api/v1/dashboard/related/owners?filter=${input}`, + endpoint: `/api/v1/dashboard/related/owners?q=${query}`, }).then( response => { const options = response.json.result.map(item => ({ diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 42cc649a9a0cf..56fe020c1552c 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -29,6 +29,7 @@ import { // @ts-ignore import Dialog from 'react-bootstrap-dialog'; import { Async as SelectAsync, Option } from 'react-select'; +import rison from 'rison'; import { t } from '@superset-ui/translation'; import { SupersetClient, Json } from '@superset-ui/connection'; import Chart from 'src/types/Chart'; @@ -112,9 +113,10 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { fetchChartData(); }, []); - const loadOptions = (input = '') => - SupersetClient.get({ - endpoint: `/api/v1/chart/related/owners?filter=${input}`, + const loadOptions = (input = '') => { + const query = rison.encode({ filter: input }); + return SupersetClient.get({ + endpoint: `/api/v1/chart/related/owners?q=${query}`, }).then( response => { const { result } = response.json as Json; @@ -129,6 +131,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { return { options: [] }; }, ); + }; const onSubmit = async (event: React.FormEvent) => { event.stopPropagation(); From 4daa3e20518ba90d0a0e3afaf23351d4ded83313 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Fri, 27 Mar 2020 14:42:38 -0700 Subject: [PATCH 03/12] fix backend owners filter logic --- .../dashboard/components/PropertiesModal.jsx | 1 + .../explore/components/PropertiesModal.tsx | 1 + superset/charts/api.py | 7 ++- superset/dashboards/api.py | 7 ++- superset/datasets/api.py | 9 ++-- superset/views/base_api.py | 32 ++++++++----- superset/views/filters.py | 46 +++++++++++++++++++ 7 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 superset/views/filters.py diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index 506fcd1475308..7f1ce3ae97acd 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -245,6 +245,7 @@ class PropertiesModal extends React.PureComponent { loadOptions={this.loadOwnerOptions} onChange={this.onOwnersChange} disabled={!isDashboardLoaded} + filterOption={() => true} // options are filtered at the api />

{t('Owners is a list of users who can alter the dashboard.')} diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 56fe020c1552c..1ac0b18b598e3 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -243,6 +243,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { loadOptions={loadOptions} onChange={setOwners} disabled={!owners} + filterOption={() => true} // options are filtered at the api />

{t('A list of users who can alter the chart')} diff --git a/superset/charts/api.py b/superset/charts/api.py index feb6e2230da98..82440a644d6bd 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -43,7 +43,8 @@ ) from superset.constants import RouteMethod from superset.models.slice import Slice -from superset.views.base_api import BaseSupersetModelRestApi +from superset.views.base_api import BaseSupersetModelRestApi, RelatedFieldFilter +from superset.views.filters import FilterRelatedOwners logger = logging.getLogger(__name__) @@ -116,7 +117,9 @@ class ChartRestApi(BaseSupersetModelRestApi): "slices": ("slice_name", "asc"), "owners": ("first_name", "asc"), } - filter_rel_fields_field = {"owners": "first_name"} + related_field_filters = { + "owners": RelatedFieldFilter("first_name", FilterRelatedOwners) + } allowed_rel_fields = {"owners"} @expose("/", methods=["POST"]) diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index e960c4cbd2b48..e3ba449536124 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -44,7 +44,8 @@ ) from superset.models.dashboard import Dashboard from superset.views.base import generate_download_headers -from superset.views.base_api import BaseSupersetModelRestApi +from superset.views.base_api import BaseSupersetModelRestApi, RelatedFieldFilter +from superset.views.filters import FilterRelatedOwners logger = logging.getLogger(__name__) @@ -113,7 +114,9 @@ class DashboardRestApi(BaseSupersetModelRestApi): "slices": ("slice_name", "asc"), "owners": ("first_name", "asc"), } - filter_rel_fields_field = {"owners": "first_name"} + related_field_filters = { + "owners": RelatedFieldFilter("username", FilterRelatedOwners) + } allowed_rel_fields = {"owners"} @expose("/", methods=["POST"]) diff --git a/superset/datasets/api.py b/superset/datasets/api.py index cab625b169959..313f3552e13e5 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -42,8 +42,9 @@ get_export_ids_schema, ) from superset.views.base import DatasourceFilter, generate_download_headers -from superset.views.base_api import BaseSupersetModelRestApi +from superset.views.base_api import BaseSupersetModelRestApi, RelatedFieldFilter from superset.views.database.filters import DatabaseFilter +from superset.views.filters import FilterRelatedOwners logger = logging.getLogger(__name__) @@ -114,8 +115,10 @@ class DatasetRestApi(BaseSupersetModelRestApi): "metrics", ] openapi_spec_tag = "Datasets" - - filter_rel_fields_field = {"owners": "first_name", "database": "database_name"} + related_field_filters = { + "owners": RelatedFieldFilter("username", FilterRelatedOwners), + "database": "database_name", + } filter_rel_fields = {"database": [["id", DatabaseFilter, lambda: []]]} allowed_rel_fields = {"database", "owners"} diff --git a/superset/views/base_api.py b/superset/views/base_api.py index 013b0fd0ecbc9..8701b6d7137ea 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -16,12 +16,13 @@ # under the License. import functools import logging -from typing import Dict, Set, Tuple +from typing import Dict, Set, Tuple, Type, Union from flask import request from flask_appbuilder import ModelRestApi from flask_appbuilder.api import expose, protect, rison, safe from flask_appbuilder.models.filters import BaseFilter, Filters +from flask_appbuilder.models.sqla.filters import FilterStartsWith from sqlalchemy.exc import SQLAlchemyError from superset.exceptions import SupersetSecurityException @@ -58,6 +59,12 @@ def wraps(self, pk): # pylint: disable=invalid-name return functools.update_wrapper(wraps, f) +class RelatedFieldFilter: + def __init__(self, field_name: str, filter_class: Type[BaseFilter]): + self.field_name = field_name + self.filter_class = filter_class + + class BaseSupersetModelRestApi(ModelRestApi): """ Extends FAB's ModelResApi to implement specific superset generic functionality @@ -86,12 +93,12 @@ class BaseSupersetModelRestApi(ModelRestApi): ... } """ # pylint: disable=pointless-string-statement - filter_rel_fields_field: Dict[str, str] = {} + related_field_filters: Dict[str, Union[RelatedFieldFilter, str]] = {} """ - Declare the related field field for filtering:: + Declare the filters for related fields:: - filter_rel_fields_field = { - "": "") + related_fields = { + "": ) } """ # pylint: disable=pointless-string-statement filter_rel_fields: Dict[str, BaseFilter] = {} @@ -125,14 +132,17 @@ def _init_properties(self): super()._init_properties() def _get_related_filter(self, datamodel, column_name: str, value: str) -> Filters: - filter_field = self.filter_rel_fields_field.get(column_name) - filters = datamodel.get_filters([filter_field]) + filter_field = self.related_field_filters.get(column_name) + if type(filter_field) is str: + filter_field = RelatedFieldFilter(filter_field, FilterStartsWith) + search_columns = [filter_field.field_name] if filter_field else None + filters = datamodel.get_filters(search_columns) base_filters = self.filter_rel_fields.get(column_name) if base_filters: - filters = filters.add_filter_list(base_filters) - if value: - filters.rest_add_filters( - [{"opr": "sw", "col": filter_field, "value": value}] + filters.add_filter_list(base_filters) + if value and filter_field: + filters.add_filter( + filter_field.field_name, filter_field.filter_class, value ) return filters diff --git a/superset/views/filters.py b/superset/views/filters.py new file mode 100644 index 0000000000000..89ee2062f1267 --- /dev/null +++ b/superset/views/filters.py @@ -0,0 +1,46 @@ +# 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. +from flask_appbuilder.models.filters import BaseFilter +from flask_babel import lazy_gettext +from sqlalchemy import or_ + +from superset import security_manager + + +class FilterRelatedOwners(BaseFilter): + """ + A filter to allow searching for related owners of a resource. + + Use in the api by adding something like: + filter_rel_fields = { + "owners": RelatedFieldFilter("username", FilterRelatedOwners), + } + """ + + name = lazy_gettext("Owner") + arg_name = "owners" + + def apply(self, query, value): + user_model = security_manager.user_model + like_value = "%" + value + "%" + return query.filter( + or_( + # could be made to handle spaces between names more gracefully + (user_model.first_name + " " + user_model.last_name).ilike(like_value), + user_model.username.ilike(like_value), + ) + ) From bd5600b8f02355af25c08293772971c694b3d630 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Tue, 31 Mar 2020 15:10:52 -0700 Subject: [PATCH 04/12] use fullname, not username on owners inputs --- .../src/dashboard/components/PropertiesModal.jsx | 2 +- .../src/explore/components/PropertiesModal.tsx | 2 +- superset/charts/api.py | 2 ++ superset/dashboards/api.py | 4 +++- superset/datasets/api.py | 4 +++- superset/views/filters.py | 12 ++++-------- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index 7f1ce3ae97acd..6141ffe511010 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -104,7 +104,7 @@ class PropertiesModal extends React.PureComponent { })); const initialSelectedOwners = dashboard.owners.map(owner => ({ value: owner.id, - label: owner.username, + label: `${owner.first_name} ${owner.last_name}`, })); this.onOwnersChange(initialSelectedOwners); }, this.handleErrorResponse); diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 1ac0b18b598e3..09531d08dace4 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -99,7 +99,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { setOwners( chart.owners.map((owner: any) => ({ value: owner.id, - label: owner.username, + label: `${owner.first_name} ${owner.last_name}`, })), ); } catch (response) { diff --git a/superset/charts/api.py b/superset/charts/api.py index 82440a644d6bd..761de3c33e936 100644 --- a/superset/charts/api.py +++ b/superset/charts/api.py @@ -66,6 +66,8 @@ class ChartRestApi(BaseSupersetModelRestApi): "description", "owners.id", "owners.username", + "owners.first_name", + "owners.last_name", "dashboards.id", "dashboards.dashboard_title", "viz_type", diff --git a/superset/dashboards/api.py b/superset/dashboards/api.py index e3ba449536124..9d5c500286d1d 100644 --- a/superset/dashboards/api.py +++ b/superset/dashboards/api.py @@ -69,6 +69,8 @@ class DashboardRestApi(BaseSupersetModelRestApi): "json_metadata", "owners.id", "owners.username", + "owners.first_name", + "owners.last_name", "changed_by_name", "changed_by_url", "changed_by.username", @@ -115,7 +117,7 @@ class DashboardRestApi(BaseSupersetModelRestApi): "owners": ("first_name", "asc"), } related_field_filters = { - "owners": RelatedFieldFilter("username", FilterRelatedOwners) + "owners": RelatedFieldFilter("first_name", FilterRelatedOwners) } allowed_rel_fields = {"owners"} diff --git a/superset/datasets/api.py b/superset/datasets/api.py index 313f3552e13e5..80ff1d3383fc1 100644 --- a/superset/datasets/api.py +++ b/superset/datasets/api.py @@ -91,6 +91,8 @@ class DatasetRestApi(BaseSupersetModelRestApi): "template_params", "owners.id", "owners.username", + "owners.first_name", + "owners.last_name", "columns", "metrics", ] @@ -116,7 +118,7 @@ class DatasetRestApi(BaseSupersetModelRestApi): ] openapi_spec_tag = "Datasets" related_field_filters = { - "owners": RelatedFieldFilter("username", FilterRelatedOwners), + "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), "database": "database_name", } filter_rel_fields = {"database": [["id", DatabaseFilter, lambda: []]]} diff --git a/superset/views/filters.py b/superset/views/filters.py index 89ee2062f1267..087e2396eaacf 100644 --- a/superset/views/filters.py +++ b/superset/views/filters.py @@ -16,7 +16,6 @@ # under the License. from flask_appbuilder.models.filters import BaseFilter from flask_babel import lazy_gettext -from sqlalchemy import or_ from superset import security_manager @@ -26,8 +25,8 @@ class FilterRelatedOwners(BaseFilter): A filter to allow searching for related owners of a resource. Use in the api by adding something like: - filter_rel_fields = { - "owners": RelatedFieldFilter("username", FilterRelatedOwners), + related_field_filters = { + "owners": RelatedFieldFilter("first_name", FilterRelatedOwners), } """ @@ -38,9 +37,6 @@ def apply(self, query, value): user_model = security_manager.user_model like_value = "%" + value + "%" return query.filter( - or_( - # could be made to handle spaces between names more gracefully - (user_model.first_name + " " + user_model.last_name).ilike(like_value), - user_model.username.ilike(like_value), - ) + # could be made to handle spaces between names more gracefully + (user_model.first_name + " " + user_model.last_name).ilike(like_value) ) From a6dafd930765ff155030c166179eba5d0d54b6cf Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Wed, 1 Apr 2020 17:01:31 -0700 Subject: [PATCH 05/12] fix some tests --- superset/views/base_api.py | 5 +++-- tests/base_api_tests.py | 7 ++++--- tests/chart_api_tests.py | 9 ++++++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/superset/views/base_api.py b/superset/views/base_api.py index 8701b6d7137ea..11df67f9bbe85 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -16,7 +16,7 @@ # under the License. import functools import logging -from typing import Dict, Set, Tuple, Type, Union +from typing import cast, Dict, Set, Tuple, Type, Union from flask import request from flask_appbuilder import ModelRestApi @@ -134,7 +134,8 @@ def _init_properties(self): def _get_related_filter(self, datamodel, column_name: str, value: str) -> Filters: filter_field = self.related_field_filters.get(column_name) if type(filter_field) is str: - filter_field = RelatedFieldFilter(filter_field, FilterStartsWith) + filter_field = RelatedFieldFilter(cast(str, filter_field), FilterStartsWith) + filter_field = cast(RelatedFieldFilter, filter_field) search_columns = [filter_field.field_name] if filter_field else None filters = datamodel.get_filters(search_columns) base_filters = self.filter_rel_fields.get(column_name) diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py index 7a0481301a304..0ebaceb065723 100644 --- a/tests/base_api_tests.py +++ b/tests/base_api_tests.py @@ -158,7 +158,7 @@ def test_get_filter_related_owners(self): API: Test get filter related owners """ self.login(username="admin") - argument = {"filter": "a"} + argument = {"filter": "gamma"} uri = f"api/v1/{self.resource_name}/related/owners?q={prison.dumps(argument)}" rv = self.client.get(uri) @@ -167,8 +167,9 @@ def test_get_filter_related_owners(self): expected_response = { "count": 2, "result": [ - {"text": "admin user", "value": 1}, - {"text": "alpha user", "value": 5}, + {"text": "gamma user", "value": 2}, + {"text": "gamma2 user", "value": 3}, + {"text": "gamma_sqllab user", "value": 4}, ], } self.assertEqual(response, expected_response) diff --git a/tests/chart_api_tests.py b/tests/chart_api_tests.py index 0afda14f24dbb..e14183fbb9672 100644 --- a/tests/chart_api_tests.py +++ b/tests/chart_api_tests.py @@ -486,7 +486,14 @@ def test_get_chart(self): "cache_timeout": None, "dashboards": [], "description": None, - "owners": [{"id": 1, "username": "admin"}], + "owners": [ + { + "id": 1, + "username": "admin", + "first_name": "admin", + "last_name": "user", + } + ], "params": None, "slice_name": "title", "viz_type": None, From c5e6568b8b950d183733308b246fc4f721e023a9 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Thu, 2 Apr 2020 23:37:30 -0700 Subject: [PATCH 06/12] fixing tests --- tests/base_api_tests.py | 2 +- tests/dashboards/api_tests.py | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py index 0ebaceb065723..2fd83a0a414fe 100644 --- a/tests/base_api_tests.py +++ b/tests/base_api_tests.py @@ -165,7 +165,7 @@ def test_get_filter_related_owners(self): self.assertEqual(rv.status_code, 200) response = json.loads(rv.data.decode("utf-8")) expected_response = { - "count": 2, + "count": 3, "result": [ {"text": "gamma user", "value": 2}, {"text": "gamma2 user", "value": 3}, diff --git a/tests/dashboards/api_tests.py b/tests/dashboards/api_tests.py index 45b588f04cc92..fcd8d11ef2814 100644 --- a/tests/dashboards/api_tests.py +++ b/tests/dashboards/api_tests.py @@ -96,7 +96,14 @@ def test_get_dashboard(self): "css": "", "dashboard_title": "title", "json_metadata": "", - "owners": [{"id": 1, "username": "admin"}], + "owners": [ + { + "id": 1, + "username": "admin", + "first_name": "admin", + "last_name": "user", + } + ], "position_json": "", "published": False, "url": f"/superset/dashboard/slug1/", From 73170b8f56a406d0852978c987c7b82e2df5c1e1 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Fri, 3 Apr 2020 13:32:59 -0700 Subject: [PATCH 07/12] deterministic tests --- tests/base_api_tests.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py index 2fd83a0a414fe..8ab63f5c6fe84 100644 --- a/tests/base_api_tests.py +++ b/tests/base_api_tests.py @@ -158,20 +158,13 @@ def test_get_filter_related_owners(self): API: Test get filter related owners """ self.login(username="admin") - argument = {"filter": "gamma"} + argument = {"filter": "mma u"} uri = f"api/v1/{self.resource_name}/related/owners?q={prison.dumps(argument)}" rv = self.client.get(uri) self.assertEqual(rv.status_code, 200) response = json.loads(rv.data.decode("utf-8")) - expected_response = { - "count": 3, - "result": [ - {"text": "gamma user", "value": 2}, - {"text": "gamma2 user", "value": 3}, - {"text": "gamma_sqllab user", "value": 4}, - ], - } + expected_response = {"count": 1, "result": [{"text": "gamma user", "value": 2}]} self.assertEqual(response, expected_response) def test_get_related_fail(self): From 8beaf8b9b91ffb590806be5479eb896cd1018d53 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Fri, 3 Apr 2020 15:39:46 -0700 Subject: [PATCH 08/12] appease linter --- superset/views/base_api.py | 4 +++- superset/views/filters.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/superset/views/base_api.py b/superset/views/base_api.py index 11df67f9bbe85..5f49780f90f23 100644 --- a/superset/views/base_api.py +++ b/superset/views/base_api.py @@ -60,6 +60,8 @@ def wraps(self, pk): # pylint: disable=invalid-name class RelatedFieldFilter: + # data class to specify what filter to use on a /related endpoint + # pylint: disable=too-few-public-methods def __init__(self, field_name: str, filter_class: Type[BaseFilter]): self.field_name = field_name self.filter_class = filter_class @@ -133,7 +135,7 @@ def _init_properties(self): def _get_related_filter(self, datamodel, column_name: str, value: str) -> Filters: filter_field = self.related_field_filters.get(column_name) - if type(filter_field) is str: + if isinstance(filter_field, str): filter_field = RelatedFieldFilter(cast(str, filter_field), FilterStartsWith) filter_field = cast(RelatedFieldFilter, filter_field) search_columns = [filter_field.field_name] if filter_field else None diff --git a/superset/views/filters.py b/superset/views/filters.py index 087e2396eaacf..20f0f82d52bea 100644 --- a/superset/views/filters.py +++ b/superset/views/filters.py @@ -19,6 +19,8 @@ from superset import security_manager +# pylint: disable=too-few-public-methods + class FilterRelatedOwners(BaseFilter): """ From bd2563c588f404c385eb21888c064c472b0e05c7 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Mon, 6 Apr 2020 14:12:17 -0700 Subject: [PATCH 09/12] add back search by username --- superset/views/filters.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/superset/views/filters.py b/superset/views/filters.py index 20f0f82d52bea..3e4d85a555b52 100644 --- a/superset/views/filters.py +++ b/superset/views/filters.py @@ -16,6 +16,7 @@ # under the License. from flask_appbuilder.models.filters import BaseFilter from flask_babel import lazy_gettext +from sqlalchemy import or_ from superset import security_manager @@ -39,6 +40,9 @@ def apply(self, query, value): user_model = security_manager.user_model like_value = "%" + value + "%" return query.filter( - # could be made to handle spaces between names more gracefully - (user_model.first_name + " " + user_model.last_name).ilike(like_value) + or_( + # could be made to handle spaces between names more gracefully + (user_model.first_name + " " + user_model.last_name).ilike(like_value), + user_model.username.ilike(like_value), + ) ) From 7ab902696b4551a21001bf299caca710647cc4af Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Mon, 6 Apr 2020 14:13:25 -0700 Subject: [PATCH 10/12] more comprehensive filter test --- tests/base_api_tests.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/base_api_tests.py b/tests/base_api_tests.py index 8ab63f5c6fe84..112211abb50e1 100644 --- a/tests/base_api_tests.py +++ b/tests/base_api_tests.py @@ -158,14 +158,20 @@ def test_get_filter_related_owners(self): API: Test get filter related owners """ self.login(username="admin") - argument = {"filter": "mma u"} + argument = {"filter": "gamma"} uri = f"api/v1/{self.resource_name}/related/owners?q={prison.dumps(argument)}" rv = self.client.get(uri) self.assertEqual(rv.status_code, 200) response = json.loads(rv.data.decode("utf-8")) - expected_response = {"count": 1, "result": [{"text": "gamma user", "value": 2}]} - self.assertEqual(response, expected_response) + self.assertEqual(3, response["count"]) + sorted_results = sorted(response["result"], key=lambda value: value["text"]) + expected_results = [ + {"text": "gamma user", "value": 2}, + {"text": "gamma2 user", "value": 3}, + {"text": "gamma_sqllab user", "value": 4}, + ] + self.assertEqual(expected_results, sorted_results) def test_get_related_fail(self): """ From 0c5ab1b32ebad9c24b93264ba7c05d05d1bbe01e Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Mon, 6 Apr 2020 14:17:53 -0700 Subject: [PATCH 11/12] add clarifying text --- superset-frontend/src/dashboard/components/PropertiesModal.jsx | 2 +- superset-frontend/src/explore/components/PropertiesModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index 6141ffe511010..ded3bf400e195 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -248,7 +248,7 @@ class PropertiesModal extends React.PureComponent { filterOption={() => true} // options are filtered at the api />

- {t('Owners is a list of users who can alter the dashboard.')} + {t('Owners is a list of users who can alter the dashboard. Searchable by name or username.')}

diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 09531d08dace4..759d9a76ca1f0 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -246,7 +246,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { filterOption={() => true} // options are filtered at the api />

- {t('A list of users who can alter the chart')} + {t('A list of users who can alter the chart. Searchable by name or username.')}

From bc2831bc64cd02d13db53427255bc732a2a4fb43 Mon Sep 17 00:00:00 2001 From: David Aaron Suddjian Date: Mon, 6 Apr 2020 18:37:11 -0700 Subject: [PATCH 12/12] formatting... --- .../src/dashboard/components/PropertiesModal.jsx | 4 +++- superset-frontend/src/explore/components/PropertiesModal.tsx | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/dashboard/components/PropertiesModal.jsx b/superset-frontend/src/dashboard/components/PropertiesModal.jsx index ded3bf400e195..9269299a9c213 100644 --- a/superset-frontend/src/dashboard/components/PropertiesModal.jsx +++ b/superset-frontend/src/dashboard/components/PropertiesModal.jsx @@ -248,7 +248,9 @@ class PropertiesModal extends React.PureComponent { filterOption={() => true} // options are filtered at the api />

- {t('Owners is a list of users who can alter the dashboard. Searchable by name or username.')} + {t( + 'Owners is a list of users who can alter the dashboard. Searchable by name or username.', + )}

diff --git a/superset-frontend/src/explore/components/PropertiesModal.tsx b/superset-frontend/src/explore/components/PropertiesModal.tsx index 759d9a76ca1f0..56ab36c04f621 100644 --- a/superset-frontend/src/explore/components/PropertiesModal.tsx +++ b/superset-frontend/src/explore/components/PropertiesModal.tsx @@ -246,7 +246,9 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) { filterOption={() => true} // options are filtered at the api />

- {t('A list of users who can alter the chart. Searchable by name or username.')} + {t( + 'A list of users who can alter the chart. Searchable by name or username.', + )}