diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json index a63746d735e..bebf63b3485 100644 --- a/superset-frontend/package-lock.json +++ b/superset-frontend/package-lock.json @@ -8847,6 +8847,21 @@ "react-lifecycles-compat": "^3.0.4" } }, + "@react-dnd/asap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz", + "integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ==" + }, + "@react-dnd/invariant": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", + "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" + }, + "@react-dnd/shallowequal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", + "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" + }, "@scarf/scarf": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.0.6.tgz", @@ -28253,11 +28268,6 @@ "integrity": "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo=", "dev": true }, - "disposables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/disposables/-/disposables-1.0.2.tgz", - "integrity": "sha1-NsamdEdfVaLWkTVnpgFETkh7S24=" - }, "distributions": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/distributions/-/distributions-1.1.0.tgz", @@ -28266,30 +28276,6 @@ "mathfn": "^1.0.0" } }, - "dnd-core": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-2.6.0.tgz", - "integrity": "sha1-ErrWbVh0LG5ffPKUP7aFlED4CcQ=", - "requires": { - "asap": "^2.0.6", - "invariant": "^2.0.0", - "lodash": "^4.2.0", - "redux": "^3.7.1" - }, - "dependencies": { - "redux": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz", - "integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==", - "requires": { - "lodash": "^4.2.1", - "lodash-es": "^4.2.1", - "loose-envify": "^1.1.0", - "symbol-observable": "^1.0.3" - } - } - } - }, "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", @@ -31264,7 +31250,7 @@ "dependencies": { "core-js": { "version": "1.2.7", - "resolved": "http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" } } @@ -45859,31 +45845,46 @@ } }, "react-dnd": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-2.6.0.tgz", - "integrity": "sha1-f6JWds+CfViokSk+PBq1naACVFo=", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", + "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", "requires": { - "disposables": "^1.0.1", - "dnd-core": "^2.6.0", - "hoist-non-react-statics": "^2.1.0", - "invariant": "^2.1.0", - "lodash": "^4.2.0", - "prop-types": "^15.5.10" + "@react-dnd/shallowequal": "^2.0.0", + "@types/hoist-non-react-statics": "^3.3.1", + "dnd-core": "^11.1.3", + "hoist-non-react-statics": "^3.3.0" }, "dependencies": { - "hoist-non-react-statics": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", - "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + "dnd-core": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", + "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", + "requires": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.0.4" + } } } }, "react-dnd-html5-backend": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-2.6.0.tgz", - "integrity": "sha1-WQzRzKeEQbsnTt1XH+9MCxbdz44=", + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", + "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", "requires": { - "lodash": "^4.2.0" + "dnd-core": "^11.1.3" + }, + "dependencies": { + "dnd-core": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", + "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", + "requires": { + "@react-dnd/asap": "^4.0.0", + "@react-dnd/invariant": "^2.0.0", + "redux": "^4.0.4" + } + } } }, "react-docgen": { diff --git a/superset-frontend/package.json b/superset-frontend/package.json index cb0957d8248..d95a87b83a1 100644 --- a/superset-frontend/package.json +++ b/superset-frontend/package.json @@ -106,7 +106,6 @@ "d3-array": "^1.2.4", "d3-color": "^1.2.0", "d3-scale": "^2.1.2", - "dnd-core": "^2.6.0", "dom-to-image": "^2.6.0", "fontsource-fira-code": "^3.0.5", "fontsource-inter": "^3.0.5", @@ -138,8 +137,8 @@ "react-checkbox-tree": "^1.5.1", "react-color": "^2.13.8", "react-datetime": "^3.0.4", - "react-dnd": "^2.5.4", - "react-dnd-html5-backend": "^2.5.4", + "react-dnd": "^11.1.3", + "react-dnd-html5-backend": "^11.1.3", "react-dom": "^16.13.0", "react-gravatar": "^2.6.1", "react-hot-loader": "^4.12.20", diff --git a/superset-frontend/spec/helpers/WithDragDropContext.jsx b/superset-frontend/spec/helpers/WithDragDropContext.jsx deleted file mode 100644 index 70a1fd36501..00000000000 --- a/superset-frontend/spec/helpers/WithDragDropContext.jsx +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import React from 'react'; -import PropTypes from 'prop-types'; - -import getDragDropManager from 'src/dashboard/util/getDragDropManager'; - -// A helper component that provides a DragDropContext for components that require it -class WithDragDropContext extends React.Component { - getChildContext() { - return { - dragDropManager: this.context.dragDropManager || getDragDropManager(), - }; - } - - render() { - return this.props.children; - } -} - -WithDragDropContext.propTypes = { - children: PropTypes.node.isRequired, -}; - -WithDragDropContext.childContextTypes = { - dragDropManager: PropTypes.object.isRequired, -}; - -export default WithDragDropContext; diff --git a/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx index 24f2f4e4e8d..2b3d04dc61a 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/DashboardBuilder_spec.jsx @@ -25,6 +25,8 @@ import { ParentSize } from '@vx/responsive'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { Sticky, StickyContainer } from 'react-sticky'; import { TabContainer, TabContent, TabPane } from 'react-bootstrap'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import BuilderComponentPane from 'src/dashboard/components/BuilderComponentPane'; import DashboardBuilder from 'src/dashboard/components/DashboardBuilder'; @@ -39,7 +41,6 @@ import { } from 'spec/fixtures/mockDashboardLayout'; import { mockStore, mockStoreWithTabs } from 'spec/fixtures/mockStore'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; const dashboardLayout = undoableDashboardLayout.present; const layoutWithTabs = undoableDashboardLayoutWithTabs.present; @@ -77,7 +78,7 @@ describe('DashboardBuilder', () => { return useProvider ? mount( - {builder} + {builder} , { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/ChartHolder_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/ChartHolder_spec.jsx index 052e0edfa4a..efc1d8ca91a 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/ChartHolder_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/ChartHolder_spec.jsx @@ -21,6 +21,8 @@ import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import Chart from 'src/dashboard/containers/Chart'; import ChartHolder from 'src/dashboard/components/gridComponents/ChartHolder'; @@ -33,7 +35,6 @@ import { getMockStore } from 'spec/fixtures/mockStore'; import { sliceId } from 'spec/fixtures/mockChartQueries'; import dashboardInfo from 'spec/fixtures/mockDashboardInfo'; import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { sliceEntitiesForChart } from 'spec/fixtures/mockSliceEntities'; describe('ChartHolder', () => { @@ -65,9 +66,9 @@ describe('ChartHolder', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Column_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Column_spec.jsx index 5000d2c98f7..7ce170ae4d2 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Column_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Column_spec.jsx @@ -21,6 +21,8 @@ import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import BackgroundStyleDropdown from 'src/dashboard/components/menu/BackgroundStyleDropdown'; import Column from 'src/dashboard/components/gridComponents/Column'; @@ -32,7 +34,6 @@ import IconButton from 'src/dashboard/components/IconButton'; import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { mockStore } from 'spec/fixtures/mockStore'; import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; @@ -66,9 +67,9 @@ describe('Column', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Divider_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Divider_spec.jsx index 876d22cdd56..3ab795265d0 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Divider_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Divider_spec.jsx @@ -19,6 +19,8 @@ import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; @@ -30,8 +32,6 @@ import { DASHBOARD_GRID_TYPE, } from 'src/dashboard/util/componentTypes'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; - describe('Divider', () => { const props = { id: 'id', @@ -49,9 +49,9 @@ describe('Divider', () => { // We have to wrap provide DragDropContext for the underlying DragDroppable // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - , + , ); return wrapper; } diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Header_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Header_spec.jsx index 0266d08a902..6f903a05c1c 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Header_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Header_spec.jsx @@ -20,6 +20,8 @@ import React from 'react'; import { Provider } from 'react-redux'; import { styledMount as mount } from 'spec/helpers/theming'; import sinon from 'sinon'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; import EditableTitle from 'src/components/EditableTitle'; @@ -33,7 +35,6 @@ import { DASHBOARD_GRID_TYPE, } from 'src/dashboard/util/componentTypes'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { mockStoreWithTabs } from 'spec/fixtures/mockStore'; describe('Header', () => { @@ -56,9 +57,9 @@ describe('Header', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , ); return wrapper; diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx index 22c7611bc5a..dc3f1b18b96 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Markdown_spec.jsx @@ -21,6 +21,9 @@ import React from 'react'; import { styledMount as mount } from 'spec/helpers/theming'; import sinon from 'sinon'; import ReactMarkdown from 'react-markdown'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; + import { act } from 'react-dom/test-utils'; import { MarkdownEditor } from 'src/components/AsyncAceEditor'; import Markdown from 'src/dashboard/components/gridComponents/Markdown'; @@ -31,7 +34,6 @@ import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import ResizableContainer from 'src/dashboard/components/resizable/ResizableContainer'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { mockStore } from 'spec/fixtures/mockStore'; import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; @@ -63,9 +65,9 @@ describe('Markdown', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , ); return wrapper; diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Row_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Row_spec.jsx index f6cd5302d19..9ece06e1801 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Row_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Row_spec.jsx @@ -20,6 +20,8 @@ import { Provider } from 'react-redux'; import React from 'react'; import { mount } from 'enzyme'; import sinon from 'sinon'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import BackgroundStyleDropdown from 'src/dashboard/components/menu/BackgroundStyleDropdown'; import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; @@ -32,7 +34,6 @@ import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; import { DASHBOARD_GRID_ID } from 'src/dashboard/util/constants'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { mockStore } from 'spec/fixtures/mockStore'; import { dashboardLayout as mockLayout } from 'spec/fixtures/mockDashboardLayout'; @@ -62,9 +63,9 @@ describe('Row', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , { wrappingComponent: ThemeProvider, diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx index e658916d858..a5c35543cf3 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tab_spec.jsx @@ -20,6 +20,8 @@ import { Provider } from 'react-redux'; import React from 'react'; import { styledMount as mount } from 'spec/helpers/theming'; import sinon from 'sinon'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; @@ -28,7 +30,6 @@ import Tab, { RENDER_TAB, RENDER_TAB_CONTENT, } from 'src/dashboard/components/gridComponents/Tab'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { dashboardLayoutWithTabs } from 'spec/fixtures/mockDashboardLayout'; import { mockStoreWithTabs } from 'spec/fixtures/mockStore'; @@ -63,9 +64,9 @@ describe('Tabs', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , ); return wrapper; diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tabs_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tabs_spec.jsx index 1b693c941b9..b9e38c6ad29 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tabs_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/Tabs_spec.jsx @@ -20,6 +20,9 @@ import { Provider } from 'react-redux'; import React from 'react'; import { shallow } from 'enzyme'; import sinon from 'sinon'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; + import { LineEditableTabs } from 'src/common/components/Tabs'; import { Modal } from 'src/common/components'; import fetchMock from 'fetch-mock'; @@ -30,7 +33,6 @@ import HoverMenu from 'src/dashboard/components/menu/HoverMenu'; import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; import Tabs from 'src/dashboard/components/gridComponents/Tabs'; import { DASHBOARD_ROOT_ID } from 'src/dashboard/util/constants'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; import { dashboardLayoutWithTabs } from 'spec/fixtures/mockDashboardLayout'; import { mockStoreWithTabs } from 'spec/fixtures/mockStore'; @@ -64,9 +66,9 @@ describe('Tabs', () => { // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - + , ); return wrapper; diff --git a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/new/DraggableNewComponent_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/new/DraggableNewComponent_spec.jsx index 804a64b1a95..2b56f02f5d9 100644 --- a/superset-frontend/spec/javascripts/dashboard/components/gridComponents/new/DraggableNewComponent_spec.jsx +++ b/superset-frontend/spec/javascripts/dashboard/components/gridComponents/new/DraggableNewComponent_spec.jsx @@ -18,6 +18,8 @@ */ import React from 'react'; import { mount } from 'enzyme'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import DragDroppable from 'src/dashboard/components/dnd/DragDroppable'; import DraggableNewComponent from 'src/dashboard/components/gridComponents/new/DraggableNewComponent'; @@ -26,7 +28,6 @@ import { NEW_COMPONENT_SOURCE_TYPE, CHART_TYPE, } from 'src/dashboard/util/componentTypes'; -import WithDragDropContext from 'spec/helpers/WithDragDropContext'; describe('DraggableNewComponent', () => { const props = { @@ -40,9 +41,9 @@ describe('DraggableNewComponent', () => { // We have to wrap provide DragDropContext for the underlying DragDroppable // otherwise we cannot assert on DragDroppable children const wrapper = mount( - + - , + , ); return wrapper; } diff --git a/superset-frontend/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx b/superset-frontend/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx index d25e1813863..9b310bda9e6 100644 --- a/superset-frontend/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx +++ b/superset-frontend/spec/javascripts/explore/components/AdhocFilterControl_spec.jsx @@ -71,7 +71,7 @@ function setup(overrides) { ...overrides, }; const wrapper = shallow(); - const component = wrapper.dive().dive().shallow(); + const component = wrapper.dive().shallow(); return { wrapper, component, onChange }; } diff --git a/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx b/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx index c76937ef1f1..45ec377f1dd 100644 --- a/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx +++ b/superset-frontend/spec/javascripts/explore/components/AdhocFilterOption_spec.jsx @@ -56,6 +56,6 @@ describe('AdhocFilterOption', () => { const popover = overlay.find(Popover); expect(popover).toHaveLength(1); expect(popover.props().defaultVisible).toBe(false); - expect(overlay.find('DraggableOptionControlLabel')).toExist(); + expect(overlay.find('OptionControlLabel')).toExist(); }); }); diff --git a/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx b/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx index 559520fc9b9..ca1651e57b5 100644 --- a/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx +++ b/superset-frontend/spec/javascripts/explore/components/AdhocMetricOption_spec.jsx @@ -60,7 +60,7 @@ describe('AdhocMetricOption', () => { it('renders an overlay trigger wrapper for the label', () => { const { wrapper } = setup(); expect(wrapper.find(Popover)).toExist(); - expect(wrapper.find('DraggableOptionControlLabel')).toExist(); + expect(wrapper.find('OptionControlLabel')).toExist(); }); it('overwrites the adhocMetric in state with onLabelChange', () => { diff --git a/superset-frontend/spec/javascripts/explore/components/MetricsControl_spec.jsx b/superset-frontend/spec/javascripts/explore/components/MetricsControl_spec.jsx index 68fdf8341d7..60017e26a85 100644 --- a/superset-frontend/spec/javascripts/explore/components/MetricsControl_spec.jsx +++ b/superset-frontend/spec/javascripts/explore/components/MetricsControl_spec.jsx @@ -55,7 +55,7 @@ function setup(overrides) { ...overrides, }; const wrapper = shallow(); - const component = wrapper.dive().dive().shallow(); + const component = wrapper.dive().shallow(); return { wrapper, component, onChange }; } diff --git a/superset-frontend/spec/javascripts/explore/components/withAsyncVerification_spec.tsx b/superset-frontend/spec/javascripts/explore/components/withAsyncVerification_spec.tsx index 355f81c43ed..39b2d86a9bc 100644 --- a/superset-frontend/spec/javascripts/explore/components/withAsyncVerification_spec.tsx +++ b/superset-frontend/spec/javascripts/explore/components/withAsyncVerification_spec.tsx @@ -120,9 +120,7 @@ describe('VerifiedMetricsControl', () => { onChange: mockOnChange, }); - const child = wrapper.find(MetricsControl) as ReactWrapper<{ - onChange: (str: string[]) => void; - }>; + const child = wrapper.find(MetricsControl); child.props().onChange(['abc']); expect(child.length).toBe(1); diff --git a/superset-frontend/src/dashboard/App.jsx b/superset-frontend/src/dashboard/App.jsx index d9057c86cd1..336473a64c8 100644 --- a/superset-frontend/src/dashboard/App.jsx +++ b/superset-frontend/src/dashboard/App.jsx @@ -20,7 +20,8 @@ import { hot } from 'react-hot-loader/root'; import React from 'react'; import { Provider } from 'react-redux'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; - +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; @@ -31,11 +32,13 @@ setupPlugins(); const App = ({ store }) => ( - - - - - + + + + + + + ); diff --git a/superset-frontend/src/dashboard/components/DashboardBuilder.jsx b/superset-frontend/src/dashboard/components/DashboardBuilder.jsx index 2c9ba0c9057..3c764b7d4f5 100644 --- a/superset-frontend/src/dashboard/components/DashboardBuilder.jsx +++ b/superset-frontend/src/dashboard/components/DashboardBuilder.jsx @@ -37,7 +37,6 @@ import DashboardComponent from 'src/dashboard/containers/DashboardComponent'; import ToastPresenter from 'src/messageToasts/containers/ToastPresenter'; import WithPopoverMenu from 'src/dashboard/components/menu/WithPopoverMenu'; -import getDragDropManager from 'src/dashboard/util/getDragDropManager'; import findTabIndexByComponentId from 'src/dashboard/util/findTabIndexByComponentId'; import getDirectPathToTabIndex from 'src/dashboard/util/getDirectPathToTabIndex'; @@ -161,12 +160,6 @@ class DashboardBuilder extends React.Component { ); } - getChildContext() { - return { - dragDropManager: this.context.dragDropManager || getDragDropManager(), - }; - } - UNSAFE_componentWillReceiveProps(nextProps) { const nextFocusComponent = getLeafComponentIdFromPath( nextProps.directPathToChild, diff --git a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx index e196f891cca..55991462aa7 100644 --- a/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx +++ b/superset-frontend/src/dashboard/components/dnd/DragDroppable.jsx @@ -155,6 +155,6 @@ UnwrappedDragDroppable.defaultProps = defaultProps; // note that the composition order here determines using // component.method() vs decoratedComponentInstance.method() in the drag/drop config -export default DropTarget(...dropConfig)( - DragSource(...dragConfig)(UnwrappedDragDroppable), +export default DragSource(...dragConfig)( + DropTarget(...dropConfig)(UnwrappedDragDroppable), ); diff --git a/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js b/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js index 196a2eb5ed0..4e13d701a54 100644 --- a/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js +++ b/superset-frontend/src/dashboard/components/dnd/dragDroppableConfig.js @@ -55,22 +55,17 @@ export const dropConfig = [ TYPE, { hover(props, monitor, component) { - if ( - component && - component.decoratedComponentInstance && - component.decoratedComponentInstance.mounted - ) { - handleHover(props, monitor, component.decoratedComponentInstance); + if (component && component.mounted) { + handleHover(props, monitor, component); } }, // note: // the react-dnd api requires that the drop() method return a result or undefined // monitor.didDrop() cannot be used because it returns true only for the most-nested target drop(props, monitor, component) { - const Component = component.decoratedComponentInstance; const dropResult = monitor.getDropResult(); - if ((!dropResult || !dropResult.destination) && Component.mounted) { - return handleDrop(props, monitor, Component); + if ((!dropResult || !dropResult.destination) && component.mounted) { + return handleDrop(props, monitor, component); } return undefined; }, diff --git a/superset-frontend/src/dashboard/util/getDragDropManager.js b/superset-frontend/src/dashboard/util/getDragDropManager.js deleted file mode 100644 index 962b82ced90..00000000000 --- a/superset-frontend/src/dashboard/util/getDragDropManager.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -import { DragDropManager } from 'dnd-core'; -import HTML5Backend from 'react-dnd-html5-backend'; - -let defaultManager; - -// we use this method to ensure that there is a singleton of the DragDropManager -// within the app this seems to work fine, but in tests multiple are initialized -// see this issue for more details https://github.com/react-dnd/react-dnd/issues/186 -// @TODO re-evaluate whether this is required when we move to jest -// the alternative is simply using an HOC like: -// DragDropContext(HTML5Backend)(DashboardBuilder); -export default function getDragDropManager() { - if (!defaultManager) { - defaultManager = new DragDropManager(HTML5Backend); - } - return defaultManager; -} diff --git a/superset-frontend/src/explore/App.jsx b/superset-frontend/src/explore/App.jsx index 71763b73b06..f0a3db4fe3f 100644 --- a/superset-frontend/src/explore/App.jsx +++ b/superset-frontend/src/explore/App.jsx @@ -19,6 +19,8 @@ import React from 'react'; import { hot } from 'react-hot-loader/root'; import { Provider } from 'react-redux'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; import ToastPresenter from '../messageToasts/containers/ToastPresenter'; @@ -33,12 +35,14 @@ setupPlugins(); const App = ({ store }) => ( - - - - - - + + + + + + + + ); diff --git a/superset-frontend/src/explore/DndContextProvider.js b/superset-frontend/src/explore/DndContextProvider.js deleted file mode 100644 index 884807ecfbc..00000000000 --- a/superset-frontend/src/explore/DndContextProvider.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -// TODO: convert to .ts after we upgrade react-dnd -import { DragDropContext } from 'react-dnd'; -import HTML5Backend from 'react-dnd-html5-backend'; - -export default DragDropContext(HTML5Backend); diff --git a/superset-frontend/src/explore/components/OptionControls.tsx b/superset-frontend/src/explore/components/OptionControls.tsx index c822b32949b..1cd683eac37 100644 --- a/superset-frontend/src/explore/components/OptionControls.tsx +++ b/superset-frontend/src/explore/components/OptionControls.tsx @@ -16,19 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -import React from 'react'; -import { findDOMNode } from 'react-dom'; -// Current version of react-dnd (2.5.4) doesn't work well with typescript -// TODO: remove ts-ignore after we upgrade react-dnd -// @ts-ignore -import { DragSource, DropTarget } from 'react-dnd'; +import React, { useRef } from 'react'; +import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd'; import { styled, useTheme } from '@superset-ui/core'; import { ColumnOption } from '@superset-ui/chart-controls'; import Icon from 'src/components/Icon'; import { savedMetricType } from 'src/explore/components/controls/MetricControl/types'; -const TYPE = 'label-dnd'; - const DragContainer = styled.div` margin-bottom: ${({ theme }) => theme.gridUnit}px; :last-child { @@ -128,93 +122,90 @@ export const AddIconButton = styled.button` } `; -const labelSource = { - beginDrag({ index, type }: { index: number; type: string }) { - return { - index, - type, - }; - }, -}; - -const labelTarget = { - hover(props: Record, monitor: any, component: any) { - const { index: dragIndex, type: dragType } = monitor.getItem(); - const { index: hoverIndex, type: hoverType } = props; - - // Don't replace items with themselves - // Don't allow to drag items between filters and metrics boxes - if (dragIndex === hoverIndex || dragType !== hoverType) { - return; - } - - // Determine rectangle on screen - // TODO: refactor with references when we upgrade react-dnd - // For now we disable warnings about findDOMNode, but we should refactor after we upgrade react-dnd - // Current version (2.5.4) doesn't work well with refs - // @ts-ignore - // eslint-disable-next-line react/no-find-dom-node - const hoverBoundingRect = findDOMNode(component)?.getBoundingClientRect(); - - // Get vertical middle - const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; - - // Determine mouse position - const clientOffset = monitor.getClientOffset(); - - // Get pixels to the top - const hoverClientY = clientOffset.y - hoverBoundingRect.top; - - // Only perform the move when the mouse has crossed half of the items height - // When dragging downwards, only move when the cursor is below 50% - // When dragging upwards, only move when the cursor is above 50% - - // Dragging downwards - if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { - return; - } - - // Dragging upwards - if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { - return; - } - - // Time to actually perform the action - props.onMoveLabel?.(dragIndex, hoverIndex); - - // Note: we're mutating the monitor item here! - // Generally it's better to avoid mutations, - // but it's good here for the sake of performance - // to avoid expensive index searches. - // eslint-disable-next-line no-param-reassign - monitor.getItem().index = hoverIndex; - }, - drop(props: Record) { - return props.onDropLabel?.(); - }, -}; +interface DragItem { + index: number; + type: string; +} export const OptionControlLabel = ({ label, savedMetric, onRemove, + onMoveLabel, + onDropLabel, isAdhoc, isFunction, - isDraggable, - connectDragSource, - connectDropTarget, + type, + index, ...props }: { label: string | React.ReactNode; savedMetric?: savedMetricType; onRemove: () => void; + onMoveLabel: (dragIndex: number, hoverIndex: number) => void; + onDropLabel: () => void; isAdhoc?: boolean; isFunction?: boolean; isDraggable?: boolean; - connectDragSource?: any; - connectDropTarget?: any; + type: string; + index: number; }) => { const theme = useTheme(); + const ref = useRef(null); + const [, drop] = useDrop({ + accept: type, + drop() { + onDropLabel?.(); + }, + hover(item: DragItem, monitor: DropTargetMonitor) { + if (!ref.current) { + return; + } + const dragIndex = item.index; + const hoverIndex = index; + // Don't replace items with themselves + if (dragIndex === hoverIndex) { + return; + } + // Determine rectangle on screen + const hoverBoundingRect = ref.current?.getBoundingClientRect(); + // Get vertical middle + const hoverMiddleY = + (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; + // Determine mouse position + const clientOffset = monitor.getClientOffset(); + // Get pixels to the top + const hoverClientY = clientOffset?.y + ? clientOffset?.y - hoverBoundingRect.top + : 0; + // Only perform the move when the mouse has crossed half of the items height + // When dragging downwards, only move when the cursor is below 50% + // When dragging upwards, only move when the cursor is above 50% + // Dragging downwards + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return; + } + // Dragging upwards + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return; + } + // Time to actually perform the action + onMoveLabel?.(dragIndex, hoverIndex); + // Note: we're mutating the monitor item here! + // Generally it's better to avoid mutations, + // but it's good here for the sake of performance + // to avoid expensive index searches. + // eslint-disable-next-line no-param-reassign + item.index = hoverIndex; + }, + }); + const [, drag] = useDrag({ + item: { type, index }, + collect: monitor => ({ + isDragging: monitor.isDragging(), + }), + }); + const getLabelContent = () => { if (savedMetric?.metric_name) { // add column_name to fix typescript error @@ -252,28 +243,6 @@ export const OptionControlLabel = ({ ); - return ( - - {isDraggable - ? connectDragSource( - connectDropTarget({getOptionControlContent()}), - ) - : getOptionControlContent()} - - ); + drag(drop(ref)); + return {getOptionControlContent()}; }; - -export const DraggableOptionControlLabel = DropTarget( - TYPE, - labelTarget, - (connect: any) => ({ - connectDropTarget: connect.dropTarget(), - }), -)( - DragSource(TYPE, labelSource, (connect: any) => ({ - connectDragSource: connect.dragSource(), - isDraggable: true, - }))(OptionControlLabel), -); - -DraggableOptionControlLabel.displayName = 'DraggableOptionControlLabel'; diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl.jsx index 2f8366be814..fd2ea23a637 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterControl.jsx @@ -34,7 +34,6 @@ import { LabelsContainer, } from 'src/explore/components/OptionControls'; import Icon from 'src/components/Icon'; -import DndWithHTML5Backend from 'src/explore/DndContextProvider'; import AdhocFilterPopoverTrigger from './AdhocFilterPopoverTrigger'; import AdhocFilterOption from './AdhocFilterOption'; import AdhocFilter, { CLAUSES, EXPRESSION_TYPES } from './AdhocFilter'; @@ -362,4 +361,4 @@ class AdhocFilterControl extends React.Component { AdhocFilterControl.propTypes = propTypes; AdhocFilterControl.defaultProps = defaultProps; -export default DndWithHTML5Backend(withTheme(AdhocFilterControl)); +export default withTheme(AdhocFilterControl); diff --git a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption.jsx b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption.jsx index 954bb8a0a4e..bdf300e8016 100644 --- a/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption.jsx +++ b/superset-frontend/src/explore/components/controls/FilterControl/AdhocFilterOption.jsx @@ -20,7 +20,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import columnType from 'src/explore/propTypes/columnType'; import adhocMetricType from 'src/explore/components/controls/MetricControl/adhocMetricType'; -import { DraggableOptionControlLabel } from 'src/explore/components/OptionControls'; +import { OptionControlLabel } from 'src/explore/components/OptionControls'; import { OPTION_TYPES } from 'src/explore/components/optionTypes'; import AdhocFilterPopoverTrigger from './AdhocFilterPopoverTrigger'; import AdhocFilter from './AdhocFilter'; @@ -61,7 +61,7 @@ const AdhocFilterOption = ({ onFilterEdit={onFilterEdit} partitionColumn={partitionColumn} > - -