diff --git a/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx b/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx new file mode 100644 index 00000000000..4b6ef601efa --- /dev/null +++ b/superset-frontend/spec/javascripts/sqllab/SaveDatasetModal_spec.tsx @@ -0,0 +1,51 @@ +/** + * 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 { shallow } from 'enzyme'; +import { Radio, AutoComplete, Input } from 'src/common/components'; +import { SaveDatasetModal } from 'src/SqlLab/components/SaveDatasetModal'; + +describe('SaveDatasetModal', () => { + const mockedProps = { + visible: false, + onOk: () => {}, + onHide: () => {}, + handleDatasetNameChange: () => {}, + userDatasetsOwned: [], + handleSaveDatasetRadioBtnState: () => {}, + saveDatasetRadioBtnState: 1, + shouldOverwriteDataset: false, + handleOverwriteCancel: () => {}, + handleOverwriteDataset: () => {}, + handleOverwriteDatasetOption: () => {}, + defaultCreateDatasetValue: 'someDatasets', + }; + it('renders a radio group btn', () => { + const wrapper = shallow(); + expect(wrapper.find(Radio.Group)).toExist(); + }); + it('renders a autocomplete', () => { + const wrapper = shallow(); + expect(wrapper.find(AutoComplete)).toExist(); + }); + it('renders an input form ', () => { + const wrapper = shallow(); + expect(wrapper.find(Input)).toExist(); + }); +}); diff --git a/superset-frontend/src/SqlLab/components/SaveDatasetModal.tsx b/superset-frontend/src/SqlLab/components/SaveDatasetModal.tsx new file mode 100644 index 00000000000..c100dff369b --- /dev/null +++ b/superset-frontend/src/SqlLab/components/SaveDatasetModal.tsx @@ -0,0 +1,182 @@ +/** + * 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, { useState, FunctionComponent } from 'react'; +import { Radio, AutoComplete, Input } from 'src/common/components'; +import StyledModal from 'src/common/components/Modal'; +import Button from 'src/components/Button'; +import { styled } from '@superset-ui/core'; +import { RadioChangeEvent } from 'antd/lib/radio'; + +interface SaveDatasetModalProps { + visible: boolean; + onOk: () => void; + onHide: () => void; + handleDatasetNameChange: (e: React.FormEvent) => void; + userDatasetsOwned: Array>; + handleSaveDatasetRadioBtnState: (e: RadioChangeEvent) => void; + saveDatasetRadioBtnState: number; + shouldOverwriteDataset: boolean; + handleOverwriteCancel: () => void; + handleOverwriteDataset: () => void; + handleOverwriteDatasetOption: ( + data: string, + option: Record, + ) => void; + defaultCreateDatasetValue: string; +} + +const Styles = styled.div` + .smd-input { + margin-left: 45px; + width: 290px; + } + .smd-autocomplete { + margin-left: 8px; + width: 290px; + } + .smd-radio { + display: block; + height: 30px; + margin: 10px 0px; + line-height: 30px; + } +`; + +// eslint-disable-next-line no-empty-pattern +export const SaveDatasetModal: FunctionComponent = ({ + visible, + onOk, + onHide, + handleDatasetNameChange, + userDatasetsOwned, + handleSaveDatasetRadioBtnState, + saveDatasetRadioBtnState, + shouldOverwriteDataset, + handleOverwriteCancel, + handleOverwriteDataset, + handleOverwriteDatasetOption, + defaultCreateDatasetValue, +}) => { + const [options, setOptions] = useState< + { + value: string; + datasetId: number; + }[] + >([]); + + const onSearch = (searchText: string) => { + setOptions( + !searchText + ? [] + : userDatasetsOwned.map(d => ({ + value: d.datasetName, + datasetId: d.datasetId, + })), + ); + }; + + const filterAutocompleteOption = ( + inputValue: string, + option: { value: string; datasetId: number }, + ) => { + // We need to add "es7" to tsconfig for this to error to go way + // https://stackoverflow.com/questions/51811239/ts2339-property-includes-does-not-exist-on-type-string/51811417 + return option.value.includes(inputValue); + }; + + return ( + + {!shouldOverwriteDataset && ( + + )} + {shouldOverwriteDataset && ( + <> + + + + )} + + } + > + + {!shouldOverwriteDataset && ( +
+
+ Save this query as virtual dataset to continue exploring. +
+ + + Save as new + + + + Overwrite existing + + + +
+ )} + {shouldOverwriteDataset && ( +
Are you sure you want to overwrite this dataset?
+ )} +
+
+ ); +}; diff --git a/superset-frontend/src/common/components/index.tsx b/superset-frontend/src/common/components/index.tsx index 7aee6980dd6..97ddef73f24 100644 --- a/superset-frontend/src/common/components/index.tsx +++ b/superset-frontend/src/common/components/index.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { styled } from '@superset-ui/core'; // eslint-disable-next-line no-restricted-imports -import { Dropdown, Skeleton, Menu as AntdMenu } from 'antd'; +import { Menu as AntdMenu, Dropdown, Skeleton } from 'antd'; import { DropDownProps } from 'antd/lib/dropdown'; /* @@ -29,6 +29,7 @@ import { DropDownProps } from 'antd/lib/dropdown'; */ // eslint-disable-next-line no-restricted-imports export { + AutoComplete, Avatar, Button, Card, @@ -42,6 +43,7 @@ export { Select, Skeleton, Switch, + Radio, Tabs, Tooltip, } from 'antd';