From 8bdd2df938adc6c45aeb3018e7ca4127d1f0cf1c Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 2 Dec 2020 12:08:54 -0800 Subject: [PATCH 01/27] working updated list --- .../src/datasource/ChangeDatasourceModal.tsx | 26 ++++++++++++------- .../components/controls/DatasourceControl.jsx | 3 +++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 4f1597be9060..2161bdb9e4a5 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -66,13 +66,21 @@ const ChangeDatasourceModal: FunctionComponent = ({ let searchRef = useRef(null); useEffect(() => { - const selectDatasource = (datasource: any) => { + const selectDatasource = (datasource: { + type: string; + id: number; + uid: string; + }) => { SupersetClient.get({ endpoint: `/datasource/get/${datasource.type}/${datasource.id}`, }) .then(({ json }) => { + console.log(json); + console.log(datasource.uid); onDatasourceSave(json); - onChange(datasource.uid); + // onChange('1__table'); + console.log(`${datasource.id}__table`); + onChange(`${datasource.id}__table`); }) .catch(response => { getClientErrorObject(response).then( @@ -93,23 +101,23 @@ const ChangeDatasourceModal: FunctionComponent = ({ } if (!datasources) { SupersetClient.get({ - endpoint: '/superset/datasources/', + endpoint: '/api/v1/dataset/', }) .then(({ json }) => { - const data = json.map((ds: any) => ({ - rawName: ds.name, - connection: ds.connection, + const data = json.result.map((ds: any) => ({ + rawName: ds.table_name, + connection: ds.database.database_name, schema: ds.schema, name: ( selectDatasource(ds)} + onClick={() => selectDatasource({ type: 'table', ...ds })} className="datasource-link" > - {ds.name} + {ds.table_name} ), - type: ds.type, + type: 'table', })); setLoading(false); setDatasources(data); diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl.jsx index d7c2a5546a57..8b1901eae2c1 100644 --- a/superset-frontend/src/explore/components/controls/DatasourceControl.jsx +++ b/superset-frontend/src/explore/components/controls/DatasourceControl.jsx @@ -108,6 +108,9 @@ class DatasourceControl extends React.PureComponent { } onDatasourceSave(datasource) { + console.log(datasource); + console.log(this.props.onDatasourceSave); + console.log(this.props.actions.setDatasource); this.props.actions.setDatasource(datasource); if (this.props.onDatasourceSave) { this.props.onDatasourceSave(datasource); From f9284113bc4e674c72f0aa84ec00a4c8daff4d8f Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 2 Dec 2020 12:16:13 -0800 Subject: [PATCH 02/27] cleanup --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 2161bdb9e4a5..a9f4706a2f16 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -117,7 +117,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ {ds.table_name} ), - type: 'table', + type: ds.kind, })); setLoading(false); setDatasources(data); From ca6b16eff807dfc879d54fffff4ad98a8f796a7b Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 2 Dec 2020 12:22:08 -0800 Subject: [PATCH 03/27] remove console.logs --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 6 +----- .../src/explore/components/controls/DatasourceControl.jsx | 3 --- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index a9f4706a2f16..b68c8b72e0ed 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -33,7 +33,7 @@ import withToasts from '../messageToasts/enhancers/withToasts'; interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; - onChange: (id: number) => void; + onChange: (string: number) => void; onDatasourceSave: (datasource: object, errors?: Array) => {}; onHide: () => void; show: boolean; @@ -75,11 +75,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ endpoint: `/datasource/get/${datasource.type}/${datasource.id}`, }) .then(({ json }) => { - console.log(json); - console.log(datasource.uid); onDatasourceSave(json); - // onChange('1__table'); - console.log(`${datasource.id}__table`); onChange(`${datasource.id}__table`); }) .catch(response => { diff --git a/superset-frontend/src/explore/components/controls/DatasourceControl.jsx b/superset-frontend/src/explore/components/controls/DatasourceControl.jsx index 8b1901eae2c1..d7c2a5546a57 100644 --- a/superset-frontend/src/explore/components/controls/DatasourceControl.jsx +++ b/superset-frontend/src/explore/components/controls/DatasourceControl.jsx @@ -108,9 +108,6 @@ class DatasourceControl extends React.PureComponent { } onDatasourceSave(datasource) { - console.log(datasource); - console.log(this.props.onDatasourceSave); - console.log(this.props.actions.setDatasource); this.props.actions.setDatasource(datasource); if (this.props.onDatasourceSave) { this.props.onDatasourceSave(datasource); From 49ff839ef494f06e48360136c36461cd8c231708 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 2 Dec 2020 14:14:15 -0800 Subject: [PATCH 04/27] change uid --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index b68c8b72e0ed..bd3513ffeb27 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -33,7 +33,7 @@ import withToasts from '../messageToasts/enhancers/withToasts'; interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; - onChange: (string: number) => void; + onChange: (uid: string) => void; onDatasourceSave: (datasource: object, errors?: Array) => {}; onHide: () => void; show: boolean; From 388737a44d7e76d8fa00c382057b030aad7b80f9 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Sun, 6 Dec 2020 22:02:28 -0800 Subject: [PATCH 05/27] update --- .../javascripts/datasource/ChangeDatasourceModal_spec.jsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx index fed3b4bdbdc5..b8caca9f657c 100644 --- a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx @@ -80,10 +80,6 @@ describe('ChangeDatasourceModal', () => { expect(wrapper.find(Modal)).toExist(); }); - it('fetches datasources', async () => { - expect(fetchMock.calls(/superset\/datasources/)).toHaveLength(3); - }); - it('changes the datasource', async () => { act(() => { wrapper.find('.datasource-link').at(0).props().onClick(datasourceData); From c542f94c95a50b9946003524c5cc5494495e4dd4 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Mon, 7 Dec 2020 00:43:03 -0800 Subject: [PATCH 06/27] remove old test --- .../datasource/ChangeDatasourceModal_spec.jsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx index b8caca9f657c..b233a3126c17 100644 --- a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx @@ -47,7 +47,7 @@ const datasourceData = { uid: datasource.id, }; -const DATASOURCES_ENDPOINT = 'glob:*/superset/datasources/'; +const DATASOURCES_ENDPOINT = 'glob:*/api/v1/dataset/'; const DATASOURCE_ENDPOINT = `glob:*/datasource/get/${datasourceData.type}/${datasourceData.id}`; const DATASOURCE_PAYLOAD = { new: 'data' }; @@ -80,11 +80,7 @@ describe('ChangeDatasourceModal', () => { expect(wrapper.find(Modal)).toExist(); }); - it('changes the datasource', async () => { - act(() => { - wrapper.find('.datasource-link').at(0).props().onClick(datasourceData); - }); - await waitForComponentToPaint(wrapper); - expect(fetchMock.calls(/datasource\/get\/table\/7/)).toHaveLength(1); + it('fetches datasources', async () => { + expect(fetchMock.calls(/api\/v1\/dataset/)).toHaveLength(3); }); }); From 36d778264dd64663a1041490c86e3b30b648078e Mon Sep 17 00:00:00 2001 From: hughhhh Date: Mon, 7 Dec 2020 18:13:11 -0800 Subject: [PATCH 07/27] fix linting --- .../spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx index b233a3126c17..4b6912ec98b9 100644 --- a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx @@ -23,7 +23,6 @@ import fetchMock from 'fetch-mock'; import thunk from 'redux-thunk'; import sinon from 'sinon'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import { act } from 'react-dom/test-utils'; import Modal from 'src/common/components/Modal'; import ChangeDatasourceModal from 'src/datasource/ChangeDatasourceModal'; import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint'; From ef7a8d99d915126959c1f1421a6663e26e196774 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Tue, 8 Dec 2020 09:39:52 -0800 Subject: [PATCH 08/27] add confirm overwrite modal --- .../src/datasource/ChangeDatasourceModal.tsx | 115 +++++++++++------- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index bd3513ffeb27..44de34b1b5f3 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -26,7 +26,8 @@ import React, { import { Alert, FormControl, FormControlProps } from 'react-bootstrap'; import { SupersetClient, t } from '@superset-ui/core'; import TableView from 'src/components/TableView'; -import Modal from 'src/common/components/Modal'; +import StyledModal from 'src/common/components/Modal'; +import Button from 'src/components/Button'; import getClientErrorObject from '../utils/getClientErrorObject'; import Loading from '../components/Loading'; import withToasts from '../messageToasts/enhancers/withToasts'; @@ -63,6 +64,8 @@ const ChangeDatasourceModal: FunctionComponent = ({ const [datasources, setDatasources] = useState(null); const [filter, setFilter] = useState(undefined); const [loading, setLoading] = useState(true); + const [confirmChange, setConfirmChange] = useState(false); + const [confirmedDataset, setConfirmedDataset] = useState(undefined); let searchRef = useRef(null); useEffect(() => { @@ -71,24 +74,8 @@ const ChangeDatasourceModal: FunctionComponent = ({ id: number; uid: string; }) => { - SupersetClient.get({ - endpoint: `/datasource/get/${datasource.type}/${datasource.id}`, - }) - .then(({ json }) => { - onDatasourceSave(json); - onChange(`${datasource.id}__table`); - }) - .catch(response => { - getClientErrorObject(response).then( - ({ error, message }: { error: any; message: string }) => { - const errorMessage = error - ? error.error || error.statusText || error - : message; - addDangerToast(errorMessage); - }, - ); - }); - onHide(); + setConfirmChange(true); + setConfirmedDataset(datasource); }; const onEnterModal = () => { @@ -152,8 +139,33 @@ const ChangeDatasourceModal: FunctionComponent = ({ [datasources, filter], ); + const handleChangeConfirm = () => { + SupersetClient.get({ + endpoint: `/datasource/get/${confirmedDataset.type}/${confirmedDataset.id}`, + }) + .then(({ json }) => { + onDatasourceSave(json); + onChange(`${confirmedDataset.id}__table`); + }) + .catch(response => { + getClientErrorObject(response).then( + ({ error, message }: { error: any; message: string }) => { + const errorMessage = error + ? error.error || error.statusText || error + : message; + addDangerToast(errorMessage); + }, + ); + }); + onHide(); + }; + + const handlerCancelConfirm = () => { + setConfirmChange(false); + }; + return ( - = ({ hideFooter > <> - - {t('Warning!')} {CHANGE_WARNING_MSG} - -
- { - setSearchRef(ref); - }} - type="text" - bsSize="sm" - value={filter} - placeholder={t('Search / Filter')} - onChange={changeSearch} - /> -
- {loading && } - {datasources && ( - + {!confirmChange && ( + <> + + {t('Warning!')} {CHANGE_WARNING_MSG} + +
+ { + setSearchRef(ref); + }} + type="text" + bsSize="sm" + value={filter} + placeholder={t('Search / Filter')} + onChange={changeSearch} + /> +
+ + {loading && } + {datasources && ( + + )} + + )} + {confirmChange && ( + <> + Warning! Changing the datasource may breakthe chart if metadata that + does not exist in the target target target datasource +
+ + +
+ )} -
+ ); }; From 85bdbefa8a684e64a27ad53af17201e9ed39eaf9 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Tue, 8 Dec 2020 15:02:15 -0800 Subject: [PATCH 09/27] fixed the test --- .../datasource/ChangeDatasourceModal_spec.jsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx index 4b6912ec98b9..19391a622234 100644 --- a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx @@ -21,6 +21,7 @@ import { mount } from 'enzyme'; import configureStore from 'redux-mock-store'; import fetchMock from 'fetch-mock'; import thunk from 'redux-thunk'; +import { act } from 'react-dom/test-utils'; import sinon from 'sinon'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import Modal from 'src/common/components/Modal'; @@ -50,7 +51,7 @@ const DATASOURCES_ENDPOINT = 'glob:*/api/v1/dataset/'; const DATASOURCE_ENDPOINT = `glob:*/datasource/get/${datasourceData.type}/${datasourceData.id}`; const DATASOURCE_PAYLOAD = { new: 'data' }; -fetchMock.get(DATASOURCES_ENDPOINT, [mockDatasource['7__table']]); +fetchMock.get(DATASOURCES_ENDPOINT, { result: [mockDatasource['7__table']] }); fetchMock.get(DATASOURCE_ENDPOINT, DATASOURCE_PAYLOAD); async function mountAndWait(props = mockedProps) { @@ -82,4 +83,12 @@ describe('ChangeDatasourceModal', () => { it('fetches datasources', async () => { expect(fetchMock.calls(/api\/v1\/dataset/)).toHaveLength(3); }); + + it('changes the datasource', async () => { + act(() => { + wrapper.find('.datasource-link').at(0).props().onClick(datasourceData); + }); + await waitForComponentToPaint(wrapper); + expect(fetchMock.calls(/datasource\/get\/table\/7/)).toHaveLength(1); + }); }); From b30a337fd9a2b2ed773c14248517c88603c0a670 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 9 Dec 2020 12:34:51 -0800 Subject: [PATCH 10/27] refactor component to have search api --- .../src/datasource/ChangeDatasourceModal.tsx | 71 ++++++++++++++++--- 1 file changed, 60 insertions(+), 11 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index bd3513ffeb27..24177b1bc076 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -22,9 +22,11 @@ import React, { useRef, useMemo, useEffect, + useCallback, } from 'react'; +import rison from 'rison'; import { Alert, FormControl, FormControlProps } from 'react-bootstrap'; -import { SupersetClient, t } from '@superset-ui/core'; +import { makeApi, SupersetClient, t } from '@superset-ui/core'; import TableView from 'src/components/TableView'; import Modal from 'src/common/components/Modal'; import getClientErrorObject from '../utils/getClientErrorObject'; @@ -65,12 +67,8 @@ const ChangeDatasourceModal: FunctionComponent = ({ const [loading, setLoading] = useState(true); let searchRef = useRef(null); - useEffect(() => { - const selectDatasource = (datasource: { - type: string; - id: number; - uid: string; - }) => { + const selectDatasource = useCallback( + (datasource: { type: string; id: number; uid: string }) => { SupersetClient.get({ endpoint: `/datasource/get/${datasource.type}/${datasource.id}`, }) @@ -89,15 +87,18 @@ const ChangeDatasourceModal: FunctionComponent = ({ ); }); onHide(); - }; + }, + [addDangerToast, onChange, onDatasourceSave, onHide], + ); + useEffect(() => { const onEnterModal = () => { if (searchRef && searchRef.current) { searchRef.current.focus(); } if (!datasources) { SupersetClient.get({ - endpoint: '/api/v1/dataset/', + endpoint: `/api/v1/dataset`, }) .then(({ json }) => { const data = json.result.map((ds: any) => ({ @@ -130,7 +131,15 @@ const ChangeDatasourceModal: FunctionComponent = ({ if (show) { onEnterModal(); } - }, [addDangerToast, datasources, onChange, onDatasourceSave, onHide, show]); + }, [ + addDangerToast, + datasources, + onChange, + onDatasourceSave, + onHide, + selectDatasource, + show, + ]); const setSearchRef = (ref: any) => { searchRef = ref; @@ -139,7 +148,47 @@ const ChangeDatasourceModal: FunctionComponent = ({ const changeSearch = ( event: React.FormEvent, ) => { - setFilter((event.currentTarget?.value as string) ?? ''); + const searchValue = (event.currentTarget?.value as string) ?? ''; + const queryParams = rison.encode({ + filters: [ + { + col: 'table_name', + opr: 'ct', + value: searchValue, + }, + ], + page_size: 0, + page: 0, + }); + + SupersetClient.get({ + endpoint: `/api/v1/dataset?q=${queryParams}`, + }) + .then(({ json }) => { + const data = json.result.map((ds: any) => ({ + rawName: ds.table_name, + connection: ds.database.database_name, + schema: ds.schema, + name: ( + selectDatasource({ type: 'table', ...ds })} + className="datasource-link" + > + {ds.table_name} + + ), + type: ds.kind, + })); + setLoading(false); + setDatasources(data); + }) + .catch(response => { + setLoading(false); + getClientErrorObject(response).then(({ error }: any) => { + addDangerToast(error.error || error.statusText || error); + }); + }); }; const data = useMemo( From ef49578960fe378467281a9e2ad52e26b9340ff5 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 9 Dec 2020 12:57:42 -0800 Subject: [PATCH 11/27] add success toast --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 94add7c6bea0..176667ea193d 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -36,6 +36,7 @@ import withToasts from '../messageToasts/enhancers/withToasts'; interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; + addSuccessToast: (msg: string) => void; onChange: (uid: string) => void; onDatasourceSave: (datasource: object, errors?: Array) => {}; onHide: () => void; @@ -58,6 +59,7 @@ const CHANGE_WARNING_MSG = t( const ChangeDatasourceModal: FunctionComponent = ({ addDangerToast, + addSuccessToast, onChange, onDatasourceSave, onHide, @@ -207,6 +209,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ ); }); onHide(); + addSuccessToast('Successfully changed datasource!') }; const handlerCancelConfirm = () => { From 7d3507ee0e943496042be29b8d70873d8417d2cd Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 9 Dec 2020 13:06:30 -0800 Subject: [PATCH 12/27] fix linting --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 176667ea193d..bfa96fc9cd2a 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -26,7 +26,7 @@ import React, { } from 'react'; import rison from 'rison'; import { Alert, FormControl, FormControlProps } from 'react-bootstrap'; -import { makeApi, SupersetClient, t } from '@superset-ui/core'; +import { SupersetClient, t } from '@superset-ui/core'; import TableView from 'src/components/TableView'; import StyledModal from 'src/common/components/Modal'; import Button from 'src/components/Button'; @@ -66,7 +66,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ show, }) => { const [datasources, setDatasources] = useState(null); - const [filter, setFilter] = useState(undefined); + const [filter] = useState(undefined); const [loading, setLoading] = useState(true); const [confirmChange, setConfirmChange] = useState(false); const [confirmedDataset, setConfirmedDataset] = useState(undefined); @@ -209,7 +209,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ ); }); onHide(); - addSuccessToast('Successfully changed datasource!') + addSuccessToast('Successfully changed datasource!'); }; const handlerCancelConfirm = () => { From da2c09b1a3c7258680b5619b13f72e0b78ad568c Mon Sep 17 00:00:00 2001 From: hughhhh Date: Wed, 9 Dec 2020 14:49:16 -0800 Subject: [PATCH 13/27] additional step for testing --- .../datasource/ChangeDatasourceModal_spec.jsx | 17 ++++++++++++++++- .../src/datasource/ChangeDatasourceModal.tsx | 9 +++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx index 19391a622234..44b4afc6e1a9 100644 --- a/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx +++ b/superset-frontend/spec/javascripts/datasource/ChangeDatasourceModal_spec.jsx @@ -84,11 +84,26 @@ describe('ChangeDatasourceModal', () => { expect(fetchMock.calls(/api\/v1\/dataset/)).toHaveLength(3); }); + it('renders confirmation message', async () => { + act(() => { + wrapper.find('.datasource-link').at(0).props().onClick(); + }); + await waitForComponentToPaint(wrapper); + + expect(wrapper.find('.proceed-btn')).toExist(); + }); + it('changes the datasource', async () => { act(() => { - wrapper.find('.datasource-link').at(0).props().onClick(datasourceData); + wrapper.find('.datasource-link').at(0).props().onClick(); }); await waitForComponentToPaint(wrapper); + + act(() => { + wrapper.find('.proceed-btn').at(0).props().onClick(datasourceData); + }); + await waitForComponentToPaint(wrapper); + expect(fetchMock.calls(/datasource\/get\/table\/7/)).toHaveLength(1); }); }); diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index bfa96fc9cd2a..6244b69c1cca 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -85,9 +85,10 @@ const ChangeDatasourceModal: FunctionComponent = ({ if (searchRef && searchRef.current) { searchRef.current.focus(); } + if (!datasources) { SupersetClient.get({ - endpoint: `/api/v1/dataset`, + endpoint: '/api/v1/dataset/', }) .then(({ json }) => { const data = json.result.map((ds: any) => ({ @@ -259,7 +260,11 @@ const ChangeDatasourceModal: FunctionComponent = ({ Warning! Changing the datasource may breakthe chart if metadata that does not exist in the target target target datasource
- From 3f839c7e45fb12a8a04adb0fc5589173c9133e46 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 10:07:44 -0800 Subject: [PATCH 14/27] refactor for hooks --- .../src/datasource/ChangeDatasourceModal.tsx | 19 ++++++++++++++++++- superset-frontend/src/types/Dataset.ts | 18 ++++++++++++++++++ superset-frontend/src/views/CRUD/hooks.ts | 2 ++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 superset-frontend/src/types/Dataset.ts diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 6244b69c1cca..a32cf1d19f07 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -34,6 +34,9 @@ import getClientErrorObject from '../utils/getClientErrorObject'; import Loading from '../components/Loading'; import withToasts from '../messageToasts/enhancers/withToasts'; +import { useListViewResource } from 'src/views/CRUD/hooks'; +import Dataset from 'src/types/Dataset'; + interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; @@ -72,6 +75,14 @@ const ChangeDatasourceModal: FunctionComponent = ({ const [confirmedDataset, setConfirmedDataset] = useState(undefined); let searchRef = useRef(null); + const { + state, + hasPerm, + fetchData, + toggleBulkSelect, + refreshData, + } = useListViewResource('dataset', t('dataset'), addDangerToast); + const selectDatasource = useCallback( (datasource: { type: string; id: number; uid: string }) => { setConfirmChange(true); @@ -81,12 +92,17 @@ const ChangeDatasourceModal: FunctionComponent = ({ ); useEffect(() => { - const onEnterModal = () => { + const onEnterModal = async () => { if (searchRef && searchRef.current) { searchRef.current.focus(); } if (!datasources) { + // prototyping + await fetchData({pageIndex: 0, pageSize: 20, filters:[], sortBy: [{id: 'changed_on_delta_humanized'}]}).then( () => { + console.log(state); + }); + SupersetClient.get({ endpoint: '/api/v1/dataset/', }) @@ -215,6 +231,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ const handlerCancelConfirm = () => { setConfirmChange(false); + console.log(state); }; return ( diff --git a/superset-frontend/src/types/Dataset.ts b/superset-frontend/src/types/Dataset.ts new file mode 100644 index 000000000000..a5ffc1cc9d6d --- /dev/null +++ b/superset-frontend/src/types/Dataset.ts @@ -0,0 +1,18 @@ +import Owner from './Owner'; + +export default interface Dataset { + changed_by_name: string; + changed_by_url: string; + changed_by: string; + changed_on_delta_humanized: string; + database: { + id: string; + database_name: string; + }; + kind: string; + explore_url: string; + id: number; + owners: Array; + schema: string; + table_name: string; +} diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index e209815aa366..66220e3c244c 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -133,6 +133,7 @@ export function useListViewResource( }) .then( ({ json = {} }) => { + console.log('about to update state', json); updateState({ collection: json.result, count: json.count, @@ -149,6 +150,7 @@ export function useListViewResource( ), ) .finally(() => { + console.log('in finally') updateState({ loading: false }); }); }, From 40b82ac5379f52432f04b47b772a92b7b4d4a361 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 10:30:49 -0800 Subject: [PATCH 15/27] switched out for hooks --- .../src/datasource/ChangeDatasourceModal.tsx | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index a32cf1d19f07..5ced7cb700a3 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -99,8 +99,11 @@ const ChangeDatasourceModal: FunctionComponent = ({ if (!datasources) { // prototyping - await fetchData({pageIndex: 0, pageSize: 20, filters:[], sortBy: [{id: 'changed_on_delta_humanized'}]}).then( () => { - console.log(state); + await fetchData({ + pageIndex: 0, + pageSize: 20, + filters: [], + sortBy: [{ id: 'changed_on_delta_humanized' }], }); SupersetClient.get({ @@ -234,6 +237,28 @@ const ChangeDatasourceModal: FunctionComponent = ({ console.log(state); }; + const renderTableView = () => { + const data = state.resourceCollection.map((ds: any) => ({ + rawName: ds.table_name, + connection: ds.database.database_name, + schema: ds.schema, + name: ( + selectDatasource({ type: 'table', ...ds })} + className="datasource-link" + > + {ds.table_name} + + ), + type: ds.kind, + })); + + console.log(data); + + return data + }; + return ( = ({
{loading && } - {datasources && ( + {state.resourceCollection.length !== 0 && ( + /> )} )} From 9535d57524a0941bffdd3445e8ae8eb69a79efce Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 10:39:09 -0800 Subject: [PATCH 16/27] update search calls --- .../src/datasource/ChangeDatasourceModal.tsx | 95 ++++--------------- superset-frontend/src/views/CRUD/hooks.ts | 2 - 2 files changed, 17 insertions(+), 80 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 5ced7cb700a3..63b248849e85 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -70,7 +70,6 @@ const ChangeDatasourceModal: FunctionComponent = ({ }) => { const [datasources, setDatasources] = useState(null); const [filter] = useState(undefined); - const [loading, setLoading] = useState(true); const [confirmChange, setConfirmChange] = useState(false); const [confirmedDataset, setConfirmedDataset] = useState(undefined); let searchRef = useRef(null); @@ -97,44 +96,13 @@ const ChangeDatasourceModal: FunctionComponent = ({ searchRef.current.focus(); } - if (!datasources) { - // prototyping - await fetchData({ - pageIndex: 0, - pageSize: 20, - filters: [], - sortBy: [{ id: 'changed_on_delta_humanized' }], - }); - - SupersetClient.get({ - endpoint: '/api/v1/dataset/', - }) - .then(({ json }) => { - const data = json.result.map((ds: any) => ({ - rawName: ds.table_name, - connection: ds.database.database_name, - schema: ds.schema, - name: ( - selectDatasource({ type: 'table', ...ds })} - className="datasource-link" - > - {ds.table_name} - - ), - type: ds.kind, - })); - setLoading(false); - setDatasources(data); - }) - .catch(response => { - setLoading(false); - getClientErrorObject(response).then(({ error }: any) => { - addDangerToast(error.error || error.statusText || error); - }); - }); - } + // Fetch initial datasets for tableview + await fetchData({ + pageIndex: 0, + pageSize: 20, + filters: [], + sortBy: [{ id: 'changed_on_delta_humanized' }], + }); }; if (show) { @@ -143,6 +111,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ }, [ addDangerToast, datasources, + fetchData, onChange, onDatasourceSave, onHide, @@ -158,46 +127,18 @@ const ChangeDatasourceModal: FunctionComponent = ({ event: React.FormEvent, ) => { const searchValue = (event.currentTarget?.value as string) ?? ''; - const queryParams = rison.encode({ + fetchData({ + pageIndex: 0, + pageSize: 20, filters: [ { - col: 'table_name', - opr: 'ct', + id: 'table_name', + operator: 'ct', value: searchValue, }, ], - page_size: 0, - page: 0, + sortBy: [{ id: 'changed_on_delta_humanized' }], }); - - SupersetClient.get({ - endpoint: `/api/v1/dataset?q=${queryParams}`, - }) - .then(({ json }) => { - const data = json.result.map((ds: any) => ({ - rawName: ds.table_name, - connection: ds.database.database_name, - schema: ds.schema, - name: ( - selectDatasource({ type: 'table', ...ds })} - className="datasource-link" - > - {ds.table_name} - - ), - type: ds.kind, - })); - setLoading(false); - setDatasources(data); - }) - .catch(response => { - setLoading(false); - getClientErrorObject(response).then(({ error }: any) => { - addDangerToast(error.error || error.statusText || error); - }); - }); }; const data = useMemo( @@ -234,7 +175,6 @@ const ChangeDatasourceModal: FunctionComponent = ({ const handlerCancelConfirm = () => { setConfirmChange(false); - console.log(state); }; const renderTableView = () => { @@ -256,7 +196,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ console.log(data); - return data + return data; }; return ( @@ -285,15 +225,14 @@ const ChangeDatasourceModal: FunctionComponent = ({ onChange={changeSearch} /> - - {loading && } + {state.loading && } {state.resourceCollection.length !== 0 && ( + /> )} )} diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index 66220e3c244c..e209815aa366 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -133,7 +133,6 @@ export function useListViewResource( }) .then( ({ json = {} }) => { - console.log('about to update state', json); updateState({ collection: json.result, count: json.count, @@ -150,7 +149,6 @@ export function useListViewResource( ), ) .finally(() => { - console.log('in finally') updateState({ loading: false }); }); }, From 011ada89de23180b401b99a907ba9bf1a8821c7c Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 10:50:49 -0800 Subject: [PATCH 17/27] cleaning things up --- .../src/datasource/ChangeDatasourceModal.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 63b248849e85..3339edad1e46 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -141,16 +141,6 @@ const ChangeDatasourceModal: FunctionComponent = ({ }); }; - const data = useMemo( - () => - filter && datasources - ? datasources.filter((datasource: any) => - TABLE_FILTERABLE.some(field => datasource[field]?.includes(filter)), - ) - : datasources, - [datasources, filter], - ); - const handleChangeConfirm = () => { SupersetClient.get({ endpoint: `/datasource/get/${confirmedDataset.type}/${confirmedDataset.id}`, From 89d9381d1d5c89876b2df3f2a9175a14099797df Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 12:33:45 -0800 Subject: [PATCH 18/27] updated component --- .../src/datasource/ChangeDatasourceModal.tsx | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 3339edad1e46..7d2722133bcc 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -20,23 +20,20 @@ import React, { FunctionComponent, useState, useRef, - useMemo, useEffect, useCallback, } from 'react'; -import rison from 'rison'; import { Alert, FormControl, FormControlProps } from 'react-bootstrap'; -import { SupersetClient, t } from '@superset-ui/core'; +import { SupersetClient, t, styled } from '@superset-ui/core'; import TableView from 'src/components/TableView'; import StyledModal from 'src/common/components/Modal'; import Button from 'src/components/Button'; +import { useListViewResource } from 'src/views/CRUD/hooks'; +import Dataset from 'src/types/Dataset'; import getClientErrorObject from '../utils/getClientErrorObject'; import Loading from '../components/Loading'; import withToasts from '../messageToasts/enhancers/withToasts'; -import { useListViewResource } from 'src/views/CRUD/hooks'; -import Dataset from 'src/types/Dataset'; - interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; @@ -46,6 +43,19 @@ interface ChangeDatasourceModalProps { show: boolean; } +const ConfirmModalStyled = styled.div` + .btn-container { + display: flex; + justify-content: flex-end; + padding: 0px 15px; + margin: 10px 0 0 0; + } + + .confirm-modal-container { + margin: 9px; + } +`; + const TABLE_COLUMNS = [ 'name', 'type', @@ -54,7 +64,6 @@ const TABLE_COLUMNS = [ 'creator', ].map(col => ({ accessor: col, Header: col })); -const TABLE_FILTERABLE = ['rawName', 'type', 'schema', 'connection', 'creator']; const CHANGE_WARNING_MSG = t( 'Changing the dataset may break the chart if the chart relies ' + 'on columns or metadata that does not exist in the target dataset', @@ -68,18 +77,14 @@ const ChangeDatasourceModal: FunctionComponent = ({ onHide, show, }) => { - const [datasources, setDatasources] = useState(null); const [filter] = useState(undefined); const [confirmChange, setConfirmChange] = useState(false); const [confirmedDataset, setConfirmedDataset] = useState(undefined); let searchRef = useRef(null); const { - state, - hasPerm, + state: { loading, resourceCollection }, fetchData, - toggleBulkSelect, - refreshData, } = useListViewResource('dataset', t('dataset'), addDangerToast); const selectDatasource = useCallback( @@ -110,7 +115,6 @@ const ChangeDatasourceModal: FunctionComponent = ({ } }, [ addDangerToast, - datasources, fetchData, onChange, onDatasourceSave, @@ -168,7 +172,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ }; const renderTableView = () => { - const data = state.resourceCollection.map((ds: any) => ({ + const data = resourceCollection.map((ds: any) => ({ rawName: ds.table_name, connection: ds.database.database_name, schema: ds.schema, @@ -184,8 +188,6 @@ const ChangeDatasourceModal: FunctionComponent = ({ type: ds.kind, })); - console.log(data); - return data; }; @@ -215,8 +217,8 @@ const ChangeDatasourceModal: FunctionComponent = ({ onChange={changeSearch} /> - {state.loading && } - {state.resourceCollection.length !== 0 && ( + {loading && } + {resourceCollection.length !== 0 && ( = ({ )} {confirmChange && ( - <> - Warning! Changing the datasource may breakthe chart if metadata that - does not exist in the target target target datasource -
- - + +
+ {t( + 'Warning! Changing the datasource may break the chart if metadata does not exist in the target datasource', + )} +
+ + +
- +
)} From e04c792569ac9e7cd030379a99dcd0016806b871 Mon Sep 17 00:00:00 2001 From: hughhhh Date: Thu, 10 Dec 2020 12:43:27 -0800 Subject: [PATCH 19/27] change messaging --- superset-frontend/src/datasource/ChangeDatasourceModal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 7d2722133bcc..935c656a85fa 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -232,9 +232,10 @@ const ChangeDatasourceModal: FunctionComponent = ({
{t( - 'Warning! Changing the datasource may break the chart if metadata does not exist in the target datasource', + 'Warning! Changing the dataset may break the chart if the metadata does not exist in the target dataset', )}
+ -
From 16e37d9b09516e5682b5cfb90ebfad82727ed89b Mon Sep 17 00:00:00 2001 From: hughhhh Date: Fri, 11 Dec 2020 09:38:05 -0800 Subject: [PATCH 20/27] use debouncing on network calls --- .../src/datasource/ChangeDatasourceModal.tsx | 58 +++++++++++++------ superset-frontend/src/types/Dataset.ts | 18 ++++++ 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx index 935c656a85fa..a59115d04611 100644 --- a/superset-frontend/src/datasource/ChangeDatasourceModal.tsx +++ b/superset-frontend/src/datasource/ChangeDatasourceModal.tsx @@ -34,6 +34,10 @@ import getClientErrorObject from '../utils/getClientErrorObject'; import Loading from '../components/Loading'; import withToasts from '../messageToasts/enhancers/withToasts'; +const CONFIRM_WARNING_MESSAGE = t( + 'Warning! Changing the dataset may break the chart if the metadata does not exist in the target dataset', +); + interface ChangeDatasourceModalProps { addDangerToast: (msg: string) => void; addSuccessToast: (msg: string) => void; @@ -69,6 +73,20 @@ const CHANGE_WARNING_MSG = t( 'on columns or metadata that does not exist in the target dataset', ); +const useDebouncedEffect = (effect, delay, deps) => { + const callback = useCallback(effect, deps); + + useEffect(() => { + const handler = setTimeout(() => { + callback(); + }, delay); + + return () => { + clearTimeout(handler); + }; + }, [callback, delay]); +}; + const ChangeDatasourceModal: FunctionComponent = ({ addDangerToast, addSuccessToast, @@ -77,7 +95,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ onHide, show, }) => { - const [filter] = useState(undefined); + const [filter, setFilter] = useState(undefined); const [confirmChange, setConfirmChange] = useState(false); const [confirmedDataset, setConfirmedDataset] = useState(undefined); let searchRef = useRef(null); @@ -95,6 +113,25 @@ const ChangeDatasourceModal: FunctionComponent = ({ [], ); + useDebouncedEffect( + () => { + fetchData({ + pageIndex: 0, + pageSize: 20, + filters: [ + { + id: 'table_name', + operator: 'ct', + value: filter, + }, + ], + sortBy: [{ id: 'changed_on_delta_humanized' }], + }); + }, + 1000, + [filter], + ); + useEffect(() => { const onEnterModal = async () => { if (searchRef && searchRef.current) { @@ -131,18 +168,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ event: React.FormEvent, ) => { const searchValue = (event.currentTarget?.value as string) ?? ''; - fetchData({ - pageIndex: 0, - pageSize: 20, - filters: [ - { - id: 'table_name', - operator: 'ct', - value: searchValue, - }, - ], - sortBy: [{ id: 'changed_on_delta_humanized' }], - }); + setFilter(searchValue); }; const handleChangeConfirm = () => { @@ -218,7 +244,7 @@ const ChangeDatasourceModal: FunctionComponent = ({ />
{loading && } - {resourceCollection.length !== 0 && ( + {!loading && ( = ({ {confirmChange && (
- {t( - 'Warning! Changing the dataset may break the chart if the metadata does not exist in the target dataset', - )} + {CONFIRM_WARNING_MESSAGE}