From 4d1d40989c333e85441fb750774bb9cc0d6c831d Mon Sep 17 00:00:00 2001 From: Lily Kuang Date: Tue, 23 Jun 2020 10:15:35 -0700 Subject: [PATCH] feat: dataset add modal (#10104) --- superset-frontend/images/icons/warning.svg | 22 +++ superset-frontend/src/components/Icon.tsx | 29 ++-- .../src/components/Menu/SubMenu.tsx | 34 +++-- .../src/components/TableSelector.jsx | 44 ++++-- .../src/views/datasetList/Button.tsx | 67 +++++++++ .../src/views/datasetList/DatasetModal.tsx | 129 ++++++++++++++++++ .../src/views/datasetList/Modal.tsx | 93 +++++++++++++ 7 files changed, 382 insertions(+), 36 deletions(-) create mode 100644 superset-frontend/images/icons/warning.svg create mode 100644 superset-frontend/src/views/datasetList/Button.tsx create mode 100644 superset-frontend/src/views/datasetList/DatasetModal.tsx create mode 100644 superset-frontend/src/views/datasetList/Modal.tsx diff --git a/superset-frontend/images/icons/warning.svg b/superset-frontend/images/icons/warning.svg new file mode 100644 index 000000000..9375f58de --- /dev/null +++ b/superset-frontend/images/icons/warning.svg @@ -0,0 +1,22 @@ + + + + + diff --git a/superset-frontend/src/components/Icon.tsx b/superset-frontend/src/components/Icon.tsx index 08a39ddf8..9040ca767 100644 --- a/superset-frontend/src/components/Icon.tsx +++ b/superset-frontend/src/components/Icon.tsx @@ -18,19 +18,20 @@ */ import React, { SVGProps } from 'react'; import styled from '@superset-ui/style'; -import { ReactComponent as CheckboxOnIcon } from 'images/icons/checkbox-on.svg'; -import { ReactComponent as CheckboxOffIcon } from 'images/icons/checkbox-off.svg'; +import { ReactComponent as CancelXIcon } from 'images/icons/cancel-x.svg'; import { ReactComponent as CheckboxHalfIcon } from 'images/icons/checkbox-half.svg'; -import { ReactComponent as SortIcon } from 'images/icons/sort.svg'; -import { ReactComponent as SortDescIcon } from 'images/icons/sort-desc.svg'; -import { ReactComponent as SortAscIcon } from 'images/icons/sort-asc.svg'; -import { ReactComponent as TrashIcon } from 'images/icons/trash.svg'; -import { ReactComponent as PencilIcon } from 'images/icons/pencil.svg'; +import { ReactComponent as CheckboxOffIcon } from 'images/icons/checkbox-off.svg'; +import { ReactComponent as CheckboxOnIcon } from 'images/icons/checkbox-on.svg'; import { ReactComponent as CompassIcon } from 'images/icons/compass.svg'; import { ReactComponent as DatasetPhysicalIcon } from 'images/icons/dataset_physical.svg'; import { ReactComponent as DatasetVirtualIcon } from 'images/icons/dataset_virtual.svg'; -import { ReactComponent as CancelXIcon } from 'images/icons/cancel-x.svg'; +import { ReactComponent as PencilIcon } from 'images/icons/pencil.svg'; import { ReactComponent as SearchIcon } from 'images/icons/search.svg'; +import { ReactComponent as SortAscIcon } from 'images/icons/sort-asc.svg'; +import { ReactComponent as SortDescIcon } from 'images/icons/sort-desc.svg'; +import { ReactComponent as SortIcon } from 'images/icons/sort.svg'; +import { ReactComponent as TrashIcon } from 'images/icons/trash.svg'; +import { ReactComponent as WarningIcon } from 'images/icons/warning.svg'; type Icon = | 'cancel-x' @@ -42,25 +43,27 @@ type Icon = | 'dataset-virtual' | 'pencil' | 'search' + | 'sort' | 'sort-asc' | 'sort-desc' - | 'sort' - | 'trash'; + | 'trash' + | 'warning'; const iconsRegistry: { [key in Icon]: React.ComponentType } = { 'cancel-x': CancelXIcon, 'checkbox-half': CheckboxHalfIcon, 'checkbox-off': CheckboxOffIcon, 'checkbox-on': CheckboxOnIcon, - compass: CompassIcon, 'dataset-physical': DatasetPhysicalIcon, 'dataset-virtual': DatasetVirtualIcon, - pencil: PencilIcon, - search: SearchIcon, 'sort-asc': SortAscIcon, 'sort-desc': SortDescIcon, + compass: CompassIcon, + pencil: PencilIcon, + search: SearchIcon, sort: SortIcon, trash: TrashIcon, + warning: WarningIcon, }; interface IconProps extends SVGProps { name: Icon; diff --git a/superset-frontend/src/components/Menu/SubMenu.tsx b/superset-frontend/src/components/Menu/SubMenu.tsx index 437deec77..f0fa2c1a4 100644 --- a/superset-frontend/src/components/Menu/SubMenu.tsx +++ b/superset-frontend/src/components/Menu/SubMenu.tsx @@ -18,6 +18,7 @@ */ import React from 'react'; import styled from '@superset-ui/style'; +import DatasetModal from 'src/views/datasetList/DatasetModal'; import { Button, Nav, Navbar, MenuItem } from 'react-bootstrap'; const StyledHeader = styled.header` @@ -62,7 +63,7 @@ const StyledHeader = styled.header` } `; -interface Props { +interface SubMenuProps { createButton: { name: string; url: string | null }; canCreate: boolean; label: string; @@ -70,13 +71,23 @@ interface Props { childs: Array<{ label: string; name: string; url: string }>; } -interface State { +interface SubMenuState { selectedMenu: string; + isModalOpen: boolean; } -class SubMenu extends React.PureComponent { - state: State = { +class SubMenu extends React.PureComponent { + state: SubMenuState = { selectedMenu: this.props.childs[0] && this.props.childs[0].label, + isModalOpen: false, + }; + + onOpen = () => { + this.setState({ isModalOpen: true }); + }; + + onClose = () => { + this.setState({ isModalOpen: false }); }; handleClick = (item: string) => () => { @@ -84,17 +95,16 @@ class SubMenu extends React.PureComponent { }; render() { - const { canCreate, childs, label, createButton } = this.props; - return ( - {label} + {this.props.label} + - {canCreate && ( + {this.props.canCreate && ( )} diff --git a/superset-frontend/src/components/TableSelector.jsx b/superset-frontend/src/components/TableSelector.jsx index 6b1ae2222..a477c85a5 100644 --- a/superset-frontend/src/components/TableSelector.jsx +++ b/superset-frontend/src/components/TableSelector.jsx @@ -17,6 +17,7 @@ * under the License. */ import React from 'react'; +import styled from '@superset-ui/style'; import PropTypes from 'prop-types'; import { Select, AsyncSelect } from 'src/components/Select'; import { ControlLabel, Label } from 'react-bootstrap'; @@ -27,6 +28,13 @@ import SupersetAsyncSelect from './AsyncSelect'; import RefreshLabel from './RefreshLabel'; import './TableSelector.less'; +const FieldTitle = styled.p` + color: ${({ theme }) => theme.colors.secondary.light2}; + font-size: ${({ theme }) => theme.typography.sizes.s}; + margin: 20px 0 10px 0; + text-transform: uppercase; +`; + const propTypes = { dbId: PropTypes.number.isRequired, schema: PropTypes.string, @@ -40,6 +48,7 @@ const propTypes = { tableName: PropTypes.string, database: PropTypes.object, sqlLabMode: PropTypes.bool, + formMode: PropTypes.bool, onChange: PropTypes.func, clearable: PropTypes.bool, handleError: PropTypes.func.isRequired, @@ -55,6 +64,7 @@ const defaultProps = { onChange: () => {}, tableNameSticky: true, sqlLabMode: true, + formMode: false, clearable: true, }; @@ -79,8 +89,10 @@ export default class TableSelector extends React.PureComponent { } componentDidMount() { - this.fetchSchemas(this.state.dbId); - this.fetchTables(); + if (this.state.dbId) { + this.fetchSchemas(this.state.dbId); + this.fetchTables(); + } } onChange() { @@ -198,7 +210,10 @@ export default class TableSelector extends React.PureComponent { this.props.onSchemaChange(null); this.props.onDbChange(db); this.fetchSchemas(dbId, force); - this.setState({ dbId, schema: null, tableOptions: [] }, this.onChange); + this.setState( + { dbId, schema: null, tableName: null, tableOptions: [] }, + this.onChange, + ); } changeSchema(schemaOpt, force = false) { @@ -289,6 +304,12 @@ export default class TableSelector extends React.PureComponent { } renderSchema() { + const refresh = !this.props.formMode && ( + this.onDatabaseChange({ id: this.props.dbId }, true)} + tooltipContent={t('Force refresh schema list')} + /> + ); return this.renderSelectRow(