Skip to content

Commit

Permalink
feat(db-connection-ui): Show Preferred DBs (#14951)
Browse files Browse the repository at this point in the history
* Creating IconButton

* Changed naming: logo is now icon

* Hard-coded inset values for ellipses

* Removed default SVG

* Fixed test

* Removed logo from test

* split db modal file

* hook up available databases

* use new validation component

* feat(db-connection-ui): Allow users to pick engine (#14884)

* poc picker for db selection

* working select

* setup is loading for available dbs and step1 view

* fix on close

* update on fetch

* remove unneeded code

* add some styls

* saving for now

* update styles

* save

* create 1 function for setting the DB

* add function to preferred section

* small refactor and added styling

* add new footer buttons

* add finsh buttong

* refactor db modal render

* fix comments issue

* add header

* add bottom footer to sqlalchemy form

* add back headers

* add step

* address comments

* oops

Co-authored-by: lyndsiWilliams <kcatgirl@gmail.com>
Co-authored-by: Elizabeth Thompson <eschutho@gmail.com>
  • Loading branch information
3 people authored Jun 4, 2021
1 parent b8e6687 commit d05814c
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 62 deletions.
3 changes: 1 addition & 2 deletions superset-frontend/src/components/IconButton/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const StyledButton = styled(Button)`
display: flex;
flex-direction: column;
padding: 0;
width: 33%;
`;
const StyledImage = styled.div`
margin: ${({ theme }) => theme.gridUnit * 8}px 0;
Expand Down Expand Up @@ -76,8 +77,6 @@ const StyledInner = styled.div`
`;

const StyledBottom = styled.div`
padding: ${({ theme }) => theme.gridUnit * 6}px
${({ theme }) => theme.gridUnit * 4}px;
border-radius: 0 0 ${({ theme }) => theme.borderRadius}px
${({ theme }) => theme.borderRadius}px;
background-color: ${({ theme }) => theme.colors.grayscale.light4};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ const DatabaseConnectionForm = ({
}) => (
<>
<StyledFormHeader>
<p className="helper"> Step 2 of 3 </p>
<h4>Enter the required {name} credentials</h4>
<p className="helper">
Need help? Learn more about connecting to {name}.
Expand Down
187 changes: 132 additions & 55 deletions superset-frontend/src/views/CRUD/data/database/DatabaseModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Tabs from 'src/components/Tabs';
import { Alert, Select } from 'src/common/components';
import Modal from 'src/components/Modal';
import Button from 'src/components/Button';
import IconButton from 'src/components/IconButton';
import withToasts from 'src/messageToasts/enhancers/withToasts';
import {
testDatabaseConnection,
Expand Down Expand Up @@ -61,6 +62,7 @@ import {
formStyles,
StyledBasicTab,
SelectDatabaseStyles,
StyledFormHeader,
} from './styles';

const DOCUMENTATION_LINK =
Expand Down Expand Up @@ -290,6 +292,76 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
}
};

const setDatabaseModel = engine => {
const isDynamic =
availableDbs?.databases.filter(db => db.engine === engine)[0]
.parameters !== undefined;
setDB({
type: ActionType.dbSelected,
payload: {
configuration_method: isDynamic
? CONFIGURATION_METHOD.DYNAMIC_FORM
: CONFIGURATION_METHOD.SQLALCHEMY_URI,
engine,
},
});
};

const renderAvailableSelector = () => (
<div className="available">
<span className="available-label">
Or choose from a list of other databases we support{' '}
</span>
<label className="label-available-select">supported databases</label>
<Select
style={{ width: '100%' }}
onChange={setDatabaseModel}
placeholder="Choose a database..."
>
{availableDbs?.databases?.map(database => (
<Select.Option value={database.engine} key={database.engine}>
{database.name}
</Select.Option>
))}
</Select>
</div>
);

const renderPreferredSelector = () => (
<div className="preferred">
{availableDbs?.databases
?.filter(db => db.preferred)
.map(database => (
<IconButton
className="preferred-item"
onClick={() => setDatabaseModel(database.engine)}
buttonText={database.name}
/>
))}
</div>
);

const renderModalFooter = () =>
db // if db show back + connect
? [
<Button
key="back"
onClick={() => {
setDB({ type: ActionType.reset });
}}
>
Back
</Button>,
!hasConnectedDb ? ( // if hasConnectedDb show back + finish
<Button key="submit" type="primary" onClick={onSave}>
Connect
</Button>
) : (
<Button onClick={onClose}>Finish</Button>
),
]
: [];

useEffect(() => {
if (show) {
setTabKey(DEFAULT_TAB_KEY);
Expand Down Expand Up @@ -359,15 +431,18 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
title={
<h4>{isEditMode ? t('Edit database') : t('Connect a database')}</h4>
}
footer={renderModalFooter()}
>
{isEditMode ? (
{isEditMode && (
<TabHeader>
<EditHeaderTitle>{db?.backend}</EditHeaderTitle>
<EditHeaderSubtitle>{dbName}</EditHeaderSubtitle>
</TabHeader>
) : (
// TODO: Fix headers when we get rid of tabs
)}
{/* Show Legacy Header */}
{useSqlAlchemyForm && (
<TabHeader>
<p className="helper"> Step 2 of 2 </p>
<CreateHeaderTitle>Enter Primary Credentials</CreateHeaderTitle>
<CreateHeaderSubtitle>
Need help? Learn how to connect your database{' '}
Expand All @@ -382,6 +457,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
</CreateHeaderSubtitle>
</TabHeader>
)}
{/* Add styled header here when not in edit mode */}
<hr />
<Tabs
defaultActiveKey={DEFAULT_TAB_KEY}
Expand Down Expand Up @@ -492,6 +568,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
width="500px"
show={show}
title={<h4>{t('Connect a database')}</h4>}
footer={renderModalFooter()}
>
{hasConnectedDb ? (
<ExtraOptions
Expand All @@ -516,65 +593,65 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
/>
) : (
<>
<DatabaseConnectionForm
db={db}
dbModel={dbModel}
onParametersChange={({ target }: { target: HTMLInputElement }) =>
onChange(ActionType.parametersChange, {
type: target.type,
name: target.name,
checked: target.checked,
value: target.value,
})
}
onChange={({ target }: { target: HTMLInputElement }) =>
onChange(ActionType.textChange, {
name: target.name,
value: target.value,
})
}
getValidation={() => getValidation(db)}
validationErrors={validationErrors}
/>
{/* Step 1 */}
{!isLoading && !db && (
<SelectDatabaseStyles>
<Label className="label-select">
What database would you like to connect?
</Label>
<Select
style={{ width: '100%' }}
onChange={(option: string) => {
<StyledFormHeader>
<div className="select-db">
<p className="helper"> Step 1 of 3 </p>
<h4>Select a database to connect</h4>
</div>
</StyledFormHeader>
{renderPreferredSelector()}
{renderAvailableSelector()}
</SelectDatabaseStyles>
)}
{/* Step 1 */}

{/* Step 2 */}
{!isLoading && db && (
<>
<DatabaseConnectionForm
dbModel={dbModel}
onParametersChange={({
target,
}: {
target: HTMLInputElement;
}) =>
onChange(ActionType.parametersChange, {
type: target.type,
name: target.name,
checked: target.checked,
value: target.value,
})
}
onChange={({ target }: { target: HTMLInputElement }) =>
onChange(ActionType.textChange, {
name: target.name,
value: target.value,
})
}
getValidation={() => getValidation(db)}
validationErrors={validationErrors}
/>

<Button
buttonStyle="link"
onClick={() =>
setDB({
type: ActionType.dbSelected,
type: ActionType.configMethodChange,
payload: {
configuration_method: CONFIGURATION_METHOD.DYNAMIC_FORM,
engine: option,
configuration_method: CONFIGURATION_METHOD.SQLALCHEMY_URI,
},
});
}}
})
}
css={buttonLinkStyles}
>
{availableDbs?.databases?.map((database: DatabaseForm) => (
<Select.Option value={database.engine} key={database.engine}>
{database.name}
</Select.Option>
))}
</Select>
</SelectDatabaseStyles>
Connect this database with a SQLAlchemy URI string instead
</Button>
{/* Step 2 */}
</>
)}
<Button
buttonStyle="link"
onClick={() =>
setDB({
type: ActionType.configMethodChange,
payload: {
configuration_method: CONFIGURATION_METHOD.SQLALCHEMY_URI,
},
})
}
css={buttonLinkStyles}
>
Connect this database with a SQLAlchemy URI string instead
</Button>
</>
)}
</Modal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ export const StyledFormHeader = styled.header`
font-weight: bold;
font-size: ${({ theme }) => theme.typography.sizes.l}px;
}
.select-db {
.helper {
margin-top: 0;
}
h4 {
margin: 0 0 29px;
}
}
`;

export const antdCollapseStyles = (theme: SupersetTheme) => css`
Expand Down Expand Up @@ -312,6 +321,12 @@ export const TabHeader = styled.div`
padding: 0px;
margin: 0 ${({ theme }) => theme.gridUnit * 4}px
${({ theme }) => theme.gridUnit * 8}px;
.helper {
color: ${({ theme }) => theme.colors.grayscale.base};
font-size: ${({ theme }) => theme.typography.sizes.s - 1}px;
margin: 0px;
}
`;

export const CreateHeaderTitle = styled.div`
Expand Down Expand Up @@ -339,5 +354,30 @@ export const EditHeaderSubtitle = styled.div`
`;

export const SelectDatabaseStyles = styled.div`
margin: ${({ theme }) => theme.gridUnit * 4}px;
margin: 0 ${({ theme }) => theme.gridUnit * 8}px;
.preferred {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
margin-bottom: ${({ theme }) => theme.gridUnit * 16}px;
}
.preferred-item {
width: 133px;
height: 133px;
}
.available {
.available-label {
font-weight: bold;
margin-top: ${({ theme }) => theme.gridUnit * 16}px;
margin-bottom: ${({ theme }) => theme.gridUnit * 8}px;
}
}
.label-available-select {
text-transform: uppercase;
font-size: ${({ theme }) => theme.typography.sizes.s - 1}px;
}
`;
8 changes: 4 additions & 4 deletions superset/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -1075,10 +1075,10 @@ def CSV_TO_HIVE_UPLOAD_DIRECTORY_FUNC(
# use the "engine_name" attribute of the corresponding DB engine spec
# in `superset/db_engine_specs/`.
PREFERRED_DATABASES: List[str] = [
# "PostgreSQL",
# "Presto",
# "MySQL",
# "SQLite",
"PostgreSQL",
"Presto",
"MySQL",
"SQLite",
# etc.
]

Expand Down

0 comments on commit d05814c

Please sign in to comment.