mirror of https://github.com/apache/superset.git
feat: restyle database modal (#14092)
* restyle database modal * change name of tab to Basic * update test with RTL better RTL render statement * change color and position of required asterisk * refactor db logic
This commit is contained in:
parent
97e086051c
commit
ff665fa5a7
|
@ -23,7 +23,6 @@ import * as redux from 'react-redux';
|
|||
import { styledMount as mount } from 'spec/helpers/theming';
|
||||
import { render, screen } from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||
import { Provider } from 'react-redux';
|
||||
import DatabaseModal from 'src/views/CRUD/data/database/DatabaseModal';
|
||||
import Modal from 'src/components/Modal';
|
||||
|
@ -87,9 +86,9 @@ describe('DatabaseModal', () => {
|
|||
it('renders a Tabs menu', () => {
|
||||
expect(wrapper.find(Tabs)).toExist();
|
||||
});
|
||||
it('renders five TabPanes', () => {
|
||||
expect(wrapper.find(Tabs.TabPane)).toExist();
|
||||
expect(wrapper.find(Tabs.TabPane)).toHaveLength(5);
|
||||
it('renders two TabPanes', () => {
|
||||
expect(wrapper.find('.ant-tabs-tab')).toExist();
|
||||
expect(wrapper.find('.ant-tabs-tab')).toHaveLength(2);
|
||||
});
|
||||
it('renders input elements for Connection section', () => {
|
||||
expect(wrapper.find('input[name="database_name"]')).toExist();
|
||||
|
@ -101,22 +100,24 @@ describe('DatabaseModal', () => {
|
|||
describe('initial load', () => {
|
||||
it('hides the forms from the db when not selected', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<Provider store={store}>
|
||||
<DatabaseModal
|
||||
show
|
||||
database={{
|
||||
expose_in_sqllab: false,
|
||||
allow_ctas: false,
|
||||
allow_cvas: false,
|
||||
}}
|
||||
/>
|
||||
</Provider>
|
||||
</ThemeProvider>,
|
||||
<DatabaseModal
|
||||
show
|
||||
database={{
|
||||
expose_in_sqllab: false,
|
||||
allow_ctas: false,
|
||||
allow_cvas: false,
|
||||
}}
|
||||
/>,
|
||||
{ useRedux: true },
|
||||
);
|
||||
// Select SQL Lab settings tab
|
||||
// Select Advanced tab
|
||||
const advancedTab = screen.getByRole('tab', {
|
||||
name: /advanced/i,
|
||||
});
|
||||
userEvent.click(advancedTab);
|
||||
// Select SQL Lab tab
|
||||
const sqlLabSettingsTab = screen.getByRole('tab', {
|
||||
name: /sql lab settings/i,
|
||||
name: /sql lab/i,
|
||||
});
|
||||
userEvent.click(sqlLabSettingsTab);
|
||||
|
||||
|
@ -129,21 +130,22 @@ describe('DatabaseModal', () => {
|
|||
});
|
||||
});
|
||||
it('renders all settings when "Expose in SQL Lab" is checked', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<Provider store={store}>
|
||||
<DatabaseModal {...dbProps} />
|
||||
</Provider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
render(<DatabaseModal {...dbProps} />, { useRedux: true });
|
||||
|
||||
// Select SQL Lab settings tab
|
||||
// Select Advanced tab
|
||||
const advancedTab = screen.getByRole('tab', {
|
||||
name: /advanced/i,
|
||||
});
|
||||
userEvent.click(advancedTab);
|
||||
|
||||
// Select SQL Lab tab
|
||||
const sqlLabSettingsTab = screen.getByRole('tab', {
|
||||
name: /sql lab settings/i,
|
||||
name: /sql lab/i,
|
||||
});
|
||||
|
||||
userEvent.click(sqlLabSettingsTab);
|
||||
// Grab all SQL Lab Settings by their labels
|
||||
|
||||
// Grab all SQL Lab settings by their labels
|
||||
// const exposeInSqlLab = screen.getByText('Expose in SQL Lab');
|
||||
const exposeInSqlLab = screen.getByRole('checkbox', {
|
||||
name: /expose in sql lab/i,
|
||||
|
@ -165,17 +167,17 @@ describe('DatabaseModal', () => {
|
|||
});
|
||||
|
||||
it('renders the schema field when allowCTAS is checked', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<Provider store={store}>
|
||||
<DatabaseModal {...dbProps} />
|
||||
</Provider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
render(<DatabaseModal {...dbProps} />, { useRedux: true });
|
||||
|
||||
// Select SQL Lab settings tab
|
||||
// Select Advanced tab
|
||||
const advancedTab = screen.getByRole('tab', {
|
||||
name: /advanced/i,
|
||||
});
|
||||
userEvent.click(advancedTab);
|
||||
|
||||
// Select SQL Lab tab
|
||||
const sqlLabSettingsTab = screen.getByRole('tab', {
|
||||
name: /sql lab settings/i,
|
||||
name: /sql lab/i,
|
||||
});
|
||||
userEvent.click(sqlLabSettingsTab);
|
||||
// Grab CTAS & schema field by their labels
|
||||
|
@ -195,17 +197,17 @@ describe('DatabaseModal', () => {
|
|||
});
|
||||
|
||||
it('renders the schema field when allowCVAS is checked', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<Provider store={store}>
|
||||
<DatabaseModal {...dbProps} />
|
||||
</Provider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
render(<DatabaseModal {...dbProps} />, { useRedux: true });
|
||||
|
||||
// Select SQL Lab settings tab
|
||||
// Select Advanced tab
|
||||
const advancedTab = screen.getByRole('tab', {
|
||||
name: /advanced/i,
|
||||
});
|
||||
userEvent.click(advancedTab);
|
||||
|
||||
// Select SQL Lab tab
|
||||
const sqlLabSettingsTab = screen.getByRole('tab', {
|
||||
name: /sql lab settings/i,
|
||||
name: /sql lab/i,
|
||||
});
|
||||
userEvent.click(sqlLabSettingsTab);
|
||||
// Grab CVAS by it's label & schema field
|
||||
|
@ -225,17 +227,17 @@ describe('DatabaseModal', () => {
|
|||
});
|
||||
|
||||
it('renders the schema field when both allowCTAS and allowCVAS are checked', () => {
|
||||
render(
|
||||
<ThemeProvider theme={supersetTheme}>
|
||||
<Provider store={store}>
|
||||
<DatabaseModal {...dbProps} />
|
||||
</Provider>
|
||||
</ThemeProvider>,
|
||||
);
|
||||
render(<DatabaseModal {...dbProps} />, { useRedux: true });
|
||||
|
||||
// Select SQL Lab settings tab
|
||||
// Select Advanced tab
|
||||
const advancedTab = screen.getByRole('tab', {
|
||||
name: /advanced/i,
|
||||
});
|
||||
userEvent.click(advancedTab);
|
||||
|
||||
// Select SQL Lab tab
|
||||
const sqlLabSettingsTab = screen.getByRole('tab', {
|
||||
name: /sql lab settings/i,
|
||||
name: /sql lab/i,
|
||||
});
|
||||
userEvent.click(sqlLabSettingsTab);
|
||||
// Grab CTAS and CVAS by their labels, & schema field
|
||||
|
|
|
@ -17,21 +17,27 @@
|
|||
* under the License.
|
||||
*/
|
||||
import React, { FunctionComponent, useState, useEffect } from 'react';
|
||||
import { styled, t } from '@superset-ui/core';
|
||||
import cx from 'classnames';
|
||||
import InfoTooltip from 'src/components/InfoTooltip';
|
||||
import { t, supersetTheme } from '@superset-ui/core';
|
||||
import {
|
||||
useSingleViewResource,
|
||||
testDatabaseConnection,
|
||||
} from 'src/views/CRUD/hooks';
|
||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||
import Icon from 'src/components/Icon';
|
||||
import Modal from 'src/components/Modal';
|
||||
import Tabs from 'src/common/components/Tabs';
|
||||
import Button from 'src/components/Button';
|
||||
import IndeterminateCheckbox from 'src/components/IndeterminateCheckbox';
|
||||
import { JsonEditor } from 'src/components/AsyncAceEditor';
|
||||
import Collapse from 'src/components/Collapse';
|
||||
import { DatabaseObject } from './types';
|
||||
import { useCommonConf } from './state';
|
||||
import {
|
||||
StyledModal,
|
||||
StyledInputContainer,
|
||||
StyledJsonEditor,
|
||||
StyledExpandableForm,
|
||||
StyledRequiredTab,
|
||||
} from './styles';
|
||||
|
||||
interface DatabaseModalProps {
|
||||
addDangerToast: (msg: string) => void;
|
||||
|
@ -43,118 +49,6 @@ interface DatabaseModalProps {
|
|||
}
|
||||
|
||||
const DEFAULT_TAB_KEY = '1';
|
||||
const EXPOSE_SQLLAB_FORM_HEIGHT = '270px';
|
||||
const CTAS_CVAS_SCHEMA_FORM_HEIGHT = '94px';
|
||||
|
||||
const StyledIcon = styled(Icon)`
|
||||
margin: auto ${({ theme }) => theme.gridUnit * 2}px auto 0;
|
||||
`;
|
||||
|
||||
const StyledInputContainer = styled.div`
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
|
||||
&.extra-container {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
&.expandable {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.25s;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 8}px;
|
||||
padding: 0;
|
||||
&.open {
|
||||
height: ${CTAS_CVAS_SCHEMA_FORM_HEIGHT};
|
||||
}
|
||||
}
|
||||
|
||||
.helper {
|
||||
display: block;
|
||||
padding: ${({ theme }) => theme.gridUnit}px 0;
|
||||
color: ${({ theme }) => theme.colors.grayscale.base};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.s - 1}px;
|
||||
text-align: left;
|
||||
|
||||
.required {
|
||||
margin-left: ${({ theme }) => theme.gridUnit / 2}px;
|
||||
color: ${({ theme }) => theme.colors.error.base};
|
||||
}
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: top;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
margin-top: ${({ theme }) => theme.gridUnit * 0.75}px;
|
||||
font-family: ${({ theme }) => theme.typography.families.sansSerif};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.m}px;
|
||||
}
|
||||
|
||||
i {
|
||||
margin: 0 ${({ theme }) => theme.gridUnit}px;
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 160px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
}
|
||||
|
||||
textarea,
|
||||
input[type='text'],
|
||||
input[type='number'] {
|
||||
padding: ${({ theme }) => theme.gridUnit * 1.5}px
|
||||
${({ theme }) => theme.gridUnit * 2}px;
|
||||
border-style: none;
|
||||
border: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||
border-radius: ${({ theme }) => theme.gridUnit}px;
|
||||
|
||||
&[name='name'] {
|
||||
flex: 0 1 auto;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
&[name='sqlalchemy_uri'] {
|
||||
margin-right: ${({ theme }) => theme.gridUnit * 3}px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledJsonEditor = styled(JsonEditor)`
|
||||
flex: 1 1 auto;
|
||||
border: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||
border-radius: ${({ theme }) => theme.gridUnit}px;
|
||||
`;
|
||||
|
||||
const StyledExpandableForm = styled.div`
|
||||
padding-top: ${({ theme }) => theme.gridUnit}px;
|
||||
.input-container {
|
||||
padding-top: ${({ theme }) => theme.gridUnit}px;
|
||||
padding-bottom: ${({ theme }) => theme.gridUnit}px;
|
||||
}
|
||||
&.expandable {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.25s;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 7}px;
|
||||
&.open {
|
||||
height: ${EXPOSE_SQLLAB_FORM_HEIGHT};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
||||
addDangerToast,
|
||||
|
@ -196,14 +90,11 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
|
||||
const connection = {
|
||||
sqlalchemy_uri: db ? db.sqlalchemy_uri : '',
|
||||
database_name:
|
||||
db && db.database_name.trim().length
|
||||
? db.database_name.trim()
|
||||
: undefined,
|
||||
impersonate_user: db ? db.impersonate_user || undefined : undefined,
|
||||
extra: db && db.extra && db.extra.length ? db.extra : undefined,
|
||||
encrypted_extra: db ? db.encrypted_extra || undefined : undefined,
|
||||
server_cert: db ? db.server_cert || undefined : undefined,
|
||||
database_name: db?.database_name?.trim() || undefined,
|
||||
impersonate_user: db?.impersonate_user || undefined,
|
||||
extra: db?.extra || undefined,
|
||||
encrypted_extra: db?.encrypted_extra || undefined,
|
||||
server_cert: db?.server_cert || undefined,
|
||||
};
|
||||
|
||||
testDatabaseConnection(connection, addDangerToast, addSuccessToast);
|
||||
|
@ -219,8 +110,8 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
if (isEditMode) {
|
||||
// Edit
|
||||
const update: DatabaseObject = {
|
||||
database_name: db ? db.database_name.trim() : '',
|
||||
sqlalchemy_uri: db ? db.sqlalchemy_uri : '',
|
||||
database_name: db?.database_name.trim() || '',
|
||||
sqlalchemy_uri: db?.sqlalchemy_uri || '',
|
||||
...db,
|
||||
};
|
||||
|
||||
|
@ -296,12 +187,7 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
};
|
||||
|
||||
const validate = () => {
|
||||
if (
|
||||
db &&
|
||||
db.database_name.trim().length &&
|
||||
db.sqlalchemy_uri &&
|
||||
db.sqlalchemy_uri.length
|
||||
) {
|
||||
if (db?.database_name?.trim() && db?.sqlalchemy_uri) {
|
||||
setDisableSave(false);
|
||||
} else {
|
||||
setDisableSave(true);
|
||||
|
@ -356,39 +242,27 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
const createAsOpen = !!(db?.allow_ctas || db?.allow_cvas);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
<StyledModal
|
||||
name="database"
|
||||
className="database-modal"
|
||||
disablePrimaryButton={disableSave}
|
||||
height="600px"
|
||||
onHandledPrimaryAction={onSave}
|
||||
onHide={hide}
|
||||
primaryButtonName={isEditMode ? t('Save') : t('Add')}
|
||||
width="750px"
|
||||
width="500px"
|
||||
show={show}
|
||||
title={
|
||||
<h4>
|
||||
<StyledIcon name="database" />
|
||||
{isEditMode ? t('Edit database') : t('Add database')}
|
||||
</h4>
|
||||
}
|
||||
title={<h4>{isEditMode ? t('Edit database') : t('Add database')}</h4>}
|
||||
>
|
||||
<Tabs
|
||||
defaultActiveKey={DEFAULT_TAB_KEY}
|
||||
activeKey={tabKey}
|
||||
onTabClick={tabChange}
|
||||
>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
{t('Connection')}
|
||||
<span className="required">*</span>
|
||||
</span>
|
||||
}
|
||||
key="1"
|
||||
>
|
||||
<StyledRequiredTab tab={<span>{t('Basic')}</span>} key="1">
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">
|
||||
{t('Database name')}
|
||||
{t('Display Name')}
|
||||
<span className="required">*</span>
|
||||
</div>
|
||||
<div className="input-container">
|
||||
|
@ -400,6 +274,9 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t('Pick a name to help you identify this database.')}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">
|
||||
|
@ -417,9 +294,6 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
)}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
<Button buttonStyle="primary" onClick={testConnection} cta>
|
||||
{t('Test connection')}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t('Refer to the ')}
|
||||
|
@ -433,300 +307,355 @@ const DatabaseModal: FunctionComponent<DatabaseModalProps> = ({
|
|||
{t(' for more information on how to structure your URI.')}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={<span>{t('Performance')}</span>} key="2">
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">{t('Chart cache timeout')}</div>
|
||||
<div className="input-container">
|
||||
<input
|
||||
type="number"
|
||||
name="cache_timeout"
|
||||
value={db?.cache_timeout || ''}
|
||||
placeholder={t('Chart cache timeout')}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'Duration (in seconds) of the caching timeout for charts of this database.' +
|
||||
' A timeout of 0 indicates that the cache never expires.' +
|
||||
' Note this defaults to the global timeout if undefined.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_run_async"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_run_async}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Asynchronous query execution')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Operate the database in asynchronous mode, meaning that the queries ' +
|
||||
'are executed on remote workers as opposed to on the web server itself. ' +
|
||||
'This assumes that you have a Celery worker setup as well as a results ' +
|
||||
'backend. Refer to the installation docs for more information.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={<span>{t('SQL Lab settings')}</span>} key="3">
|
||||
<StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="expose_in_sqllab"
|
||||
indeterminate={false}
|
||||
checked={!!db?.expose_in_sqllab}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Expose in SQL Lab')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t('Allow this database to be queried in SQL Lab')}
|
||||
/>
|
||||
</div>
|
||||
<StyledExpandableForm
|
||||
className={`expandable ${expandableModalIsOpen ? 'open' : ''}`}
|
||||
>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_ctas"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_ctas}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow CREATE TABLE AS')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow creation of new tables based on queries',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_cvas"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_cvas}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow CREATE VIEW AS')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow creation of new views based on queries',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<StyledInputContainer
|
||||
className={`expandable ${createAsOpen ? 'open' : ''}`}
|
||||
>
|
||||
<div className="control-label">
|
||||
{t('CTAS & CVAS SCHEMA')}
|
||||
</div>
|
||||
<Button
|
||||
onClick={testConnection}
|
||||
cta
|
||||
buttonStyle="link"
|
||||
style={{
|
||||
width: '100%',
|
||||
border: `1px solid ${supersetTheme.colors.primary.base}`,
|
||||
}}
|
||||
>
|
||||
{t('Test connection')}
|
||||
</Button>
|
||||
</StyledRequiredTab>
|
||||
<Tabs.TabPane tab={<span>{t('Advanced')}</span>} key="2">
|
||||
<Collapse expandIconPosition="right" accordion>
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div>
|
||||
<h4>SQL Lab</h4>
|
||||
<p className="helper">
|
||||
Configure how this database will function in SQL Lab.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
key="1"
|
||||
>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="expose_in_sqllab"
|
||||
indeterminate={false}
|
||||
checked={!!db?.expose_in_sqllab}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Expose in SQL Lab')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t('Allow this database to be queried in SQL Lab')}
|
||||
/>
|
||||
</div>
|
||||
<StyledExpandableForm
|
||||
className={cx('expandable', {
|
||||
open: expandableModalIsOpen,
|
||||
'ctas-open': createAsOpen,
|
||||
})}
|
||||
>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<input
|
||||
type="text"
|
||||
name="force_ctas_schema"
|
||||
value={db?.force_ctas_schema || ''}
|
||||
placeholder={t('Search or select schema')}
|
||||
<IndeterminateCheckbox
|
||||
id="allow_ctas"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_ctas}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow CREATE TABLE AS')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow creation of new tables based on queries',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'When allowing CREATE TABLE AS option in SQL Lab, this option ' +
|
||||
'forces the table to be created in this schema.',
|
||||
)}
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_cvas"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_cvas}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow CREATE VIEW AS')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow creation of new views based on queries',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<StyledInputContainer
|
||||
className={cx('expandable', { open: createAsOpen })}
|
||||
>
|
||||
<div className="control-label">
|
||||
{t('CTAS & CVAS SCHEMA')}
|
||||
</div>
|
||||
<div className="input-container">
|
||||
<input
|
||||
type="text"
|
||||
name="force_ctas_schema"
|
||||
value={db?.force_ctas_schema || ''}
|
||||
placeholder={t('Search or select schema')}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'When allowing CREATE TABLE AS option in SQL Lab, this option ' +
|
||||
'forces the table to be created in this schema.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_dml"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_dml}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow DML')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_dml"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_dml}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow DML')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow manipulation of the database using non-SELECT statements such as UPDATE, DELETE, CREATE, etc.',
|
||||
)}
|
||||
/>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_multi_schema_metadata_fetch"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_multi_schema_metadata_fetch}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow multi schema metadata fetch')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow SQL Lab to fetch a list of all tables and all views across all database ' +
|
||||
'schemas. For large data warehouse with thousands of tables, this can be ' +
|
||||
'expensive and put strain on the system.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</StyledExpandableForm>
|
||||
</StyledInputContainer>
|
||||
</Collapse.Panel>
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div>
|
||||
<h4>Performance</h4>
|
||||
<p className="helper">
|
||||
Adjust settings that will impact the performance of this
|
||||
database.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
key="2"
|
||||
>
|
||||
<StyledInputContainer className="mb-8">
|
||||
<div className="control-label">{t('Chart cache timeout')}</div>
|
||||
<div className="input-container">
|
||||
<input
|
||||
type="number"
|
||||
name="cache_timeout"
|
||||
value={db?.cache_timeout || ''}
|
||||
placeholder={t('Chart cache timeout')}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'Duration (in seconds) of the caching timeout for charts of this database.' +
|
||||
' A timeout of 0 indicates that the cache never expires.' +
|
||||
' Note this defaults to the global timeout if undefined.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_run_async"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_run_async}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Asynchronous query execution')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Operate the database in asynchronous mode, meaning that the queries ' +
|
||||
'are executed on remote workers as opposed to on the web server itself. ' +
|
||||
'This assumes that you have a Celery worker setup as well as a results ' +
|
||||
'backend. Refer to the installation docs for more information.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Collapse.Panel>
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div>
|
||||
<h4>Security</h4>
|
||||
<p className="helper">
|
||||
Add connection information for other systems.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
key="3"
|
||||
>
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">{t('Secure extra')}</div>
|
||||
<div className="input-container">
|
||||
<StyledJsonEditor
|
||||
name="encrypted_extra"
|
||||
value={db?.encrypted_extra || ''}
|
||||
placeholder={t('Secure extra')}
|
||||
onChange={(json: string) =>
|
||||
onEditorChange(json, 'encrypted_extra')
|
||||
}
|
||||
width="100%"
|
||||
height="160px"
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
<div>
|
||||
{t(
|
||||
'JSON string containing additional connection configuration.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_multi_schema_metadata_fetch"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_multi_schema_metadata_fetch}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow multi schema metadata fetch')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'Allow SQL Lab to fetch a list of all tables and all views across all database ' +
|
||||
'schemas. For large data warehouse with thousands of tables, this can be ' +
|
||||
'expensive and put strain on the system.',
|
||||
)}
|
||||
/>
|
||||
<div>
|
||||
{t(
|
||||
'This is used to provide connection information for systems like Hive, ' +
|
||||
'Presto, and BigQuery, which do not conform to the username:password syntax ' +
|
||||
'normally used by SQLAlchemy.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</StyledExpandableForm>
|
||||
</StyledInputContainer>
|
||||
</StyledInputContainer>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={<span>{t('Security')}</span>} key="4">
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">{t('Secure extra')}</div>
|
||||
<div className="input-container">
|
||||
<StyledJsonEditor
|
||||
name="encrypted_extra"
|
||||
value={db?.encrypted_extra || ''}
|
||||
placeholder={t('Secure extra')}
|
||||
onChange={(json: string) =>
|
||||
onEditorChange(json, 'encrypted_extra')
|
||||
}
|
||||
width="100%"
|
||||
height="160px"
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
<div>
|
||||
{t(
|
||||
'JSON string containing additional connection configuration.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'This is used to provide connection information for systems like Hive, ' +
|
||||
'Presto, and BigQuery, which do not conform to the username:password syntax ' +
|
||||
'normally used by SQLAlchemy.',
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">{t('Root certificate')}</div>
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
name="server_cert"
|
||||
value={db?.server_cert || ''}
|
||||
placeholder={t('Root certificate')}
|
||||
onChange={onTextChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'Optional CA_BUNDLE contents to validate HTTPS requests. Only available on ' +
|
||||
'certain database engines.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane tab={<span>{t('Extra')}</span>} key="5">
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="impersonate_user"
|
||||
indeterminate={false}
|
||||
checked={!!db?.impersonate_user}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Impersonate Logged In User (Presto & Hive)')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'If Presto, all the queries in SQL Lab are going to be executed as the ' +
|
||||
'currently logged on user who must have permission to run them. If Hive ' +
|
||||
'and hive.server2.enable.doAs is enabled, will run the queries as ' +
|
||||
'service account, but impersonate the currently logged on user via ' +
|
||||
'hive.server2.proxy.user property.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_csv_upload"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_csv_upload}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow data upload')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'If selected, please set the schemas allowed for data upload in Extra.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="extra-container">
|
||||
<div className="control-label">{t('Extra')}</div>
|
||||
<div className="input-container">
|
||||
<StyledJsonEditor
|
||||
name="extra"
|
||||
value={db?.extra ?? defaultExtra}
|
||||
placeholder={t('Secure extra')}
|
||||
onChange={(json: string) => onEditorChange(json, 'extra')}
|
||||
width="100%"
|
||||
height="160px"
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
<div>
|
||||
{t('JSON string containing extra configuration elements.')}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'1. The engine_params object gets unpacked into the sqlalchemy.create_engine ' +
|
||||
'call, while the metadata_params gets unpacked into the sqlalchemy.MetaData ' +
|
||||
'call.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'2. The metadata_cache_timeout is a cache timeout setting in seconds for ' +
|
||||
'metadata fetch of this database. Specify it as "metadata_cache_timeout": ' +
|
||||
'{"schema_cache_timeout": 600, "table_cache_timeout": 600}. If unset, cache ' +
|
||||
'will not be enabled for the functionality. A timeout of 0 indicates that ' +
|
||||
'the cache never expires.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'3. The schemas_allowed_for_csv_upload is a comma separated list of schemas ' +
|
||||
'that CSVs are allowed to upload to. Specify it as ' +
|
||||
'"schemas_allowed_for_csv_upload": ["public", "csv_upload"]. If database ' +
|
||||
'flavor does not support schema or any schema is allowed to be accessed, ' +
|
||||
'just leave the list empty.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
"4. The version field is a string specifying this db's version. This " +
|
||||
'should be used with Presto DBs so that the syntax is correct.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'5. The allows_virtual_table_explore field is a boolean specifying whether ' +
|
||||
'or not the Explore button in SQL Lab results is shown.',
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer>
|
||||
<div className="control-label">{t('Root certificate')}</div>
|
||||
<div className="input-container">
|
||||
<textarea
|
||||
name="server_cert"
|
||||
value={db?.server_cert || ''}
|
||||
placeholder={t('Root certificate')}
|
||||
onChange={onTextChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
{t(
|
||||
'Optional CA_BUNDLE contents to validate HTTPS requests. Only available on ' +
|
||||
'certain database engines.',
|
||||
)}
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Collapse.Panel>
|
||||
<Collapse.Panel
|
||||
header={
|
||||
<div>
|
||||
<h4>Other</h4>
|
||||
<p className="helper">Additional settings.</p>
|
||||
</div>
|
||||
}
|
||||
key="4"
|
||||
>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="impersonate_user"
|
||||
indeterminate={false}
|
||||
checked={!!db?.impersonate_user}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Impersonate Logged In User (Presto & Hive)')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'If Presto, all the queries in SQL Lab are going to be executed as the ' +
|
||||
'currently logged on user who must have permission to run them. If Hive ' +
|
||||
'and hive.server2.enable.doAs is enabled, will run the queries as ' +
|
||||
'service account, but impersonate the currently logged on user via ' +
|
||||
'hive.server2.proxy.user property.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="mb-0">
|
||||
<div className="input-container">
|
||||
<IndeterminateCheckbox
|
||||
id="allow_csv_upload"
|
||||
indeterminate={false}
|
||||
checked={!!db?.allow_csv_upload}
|
||||
onChange={onInputChange}
|
||||
labelText={t('Allow data upload')}
|
||||
/>
|
||||
<InfoTooltip
|
||||
tooltip={t(
|
||||
'If selected, please set the schemas allowed for data upload in Extra.',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
<StyledInputContainer className="extra-container">
|
||||
<div className="control-label">{t('Extra')}</div>
|
||||
<div className="input-container">
|
||||
<StyledJsonEditor
|
||||
name="extra"
|
||||
value={db?.extra ?? defaultExtra}
|
||||
placeholder={t('Secure extra')}
|
||||
onChange={(json: string) => onEditorChange(json, 'extra')}
|
||||
width="100%"
|
||||
height="160px"
|
||||
/>
|
||||
</div>
|
||||
<div className="helper">
|
||||
<div>
|
||||
{t('JSON string containing extra configuration elements.')}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'1. The engine_params object gets unpacked into the sqlalchemy.create_engine ' +
|
||||
'call, while the metadata_params gets unpacked into the sqlalchemy.MetaData ' +
|
||||
'call.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'2. The metadata_cache_timeout is a cache timeout setting in seconds for ' +
|
||||
'metadata fetch of this database. Specify it as "metadata_cache_timeout": ' +
|
||||
'{"schema_cache_timeout": 600, "table_cache_timeout": 600}. If unset, cache ' +
|
||||
'will not be enabled for the functionality. A timeout of 0 indicates that ' +
|
||||
'the cache never expires.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'3. The schemas_allowed_for_csv_upload is a comma separated list of schemas ' +
|
||||
'that CSVs are allowed to upload to. Specify it as ' +
|
||||
'"schemas_allowed_for_csv_upload": ["public", "csv_upload"]. If database ' +
|
||||
'flavor does not support schema or any schema is allowed to be accessed, ' +
|
||||
'just leave the list empty.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
"4. The version field is a string specifying this db's version. This " +
|
||||
'should be used with Presto DBs so that the syntax is correct.',
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{t(
|
||||
'5. The allows_virtual_table_explore field is a boolean specifying whether ' +
|
||||
'or not the Explore button in SQL Lab results is shown.',
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</StyledInputContainer>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Modal>
|
||||
</StyledModal>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
/**
|
||||
* 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 { styled } from '@superset-ui/core';
|
||||
import Modal from 'src/components/Modal';
|
||||
import { JsonEditor } from 'src/components/AsyncAceEditor';
|
||||
import Tabs from 'src/common/components/Tabs';
|
||||
|
||||
const CTAS_CVAS_SCHEMA_FORM_HEIGHT = 102;
|
||||
const EXPOSE_IN_SQLLAB_FORM_HEIGHT = CTAS_CVAS_SCHEMA_FORM_HEIGHT + 52;
|
||||
const EXPOSE_ALL_FORM_HEIGHT = EXPOSE_IN_SQLLAB_FORM_HEIGHT + 102;
|
||||
|
||||
const anticonHeight = 12;
|
||||
|
||||
export const StyledModal = styled(Modal)`
|
||||
.ant-collapse {
|
||||
.ant-collapse-header {
|
||||
padding-top: ${({ theme }) => theme.gridUnit * 3.5}px;
|
||||
padding-bottom: ${({ theme }) => theme.gridUnit * 2.5}px;
|
||||
|
||||
.anticon.ant-collapse-arrow {
|
||||
top: calc(50% - ${anticonHeight / 2}px);
|
||||
}
|
||||
.helper {
|
||||
color: ${({ theme }) => theme.colors.grayscale.base};
|
||||
}
|
||||
}
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-top: 0;
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit}px;
|
||||
}
|
||||
p.helper {
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
.ant-modal-header {
|
||||
padding: 18px 16px 16px;
|
||||
}
|
||||
.ant-modal-body {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.ant-tabs-top > .ant-tabs-nav {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.ant-modal-close-x .close {
|
||||
color: ${({ theme }) => theme.colors.grayscale.dark1};
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.required {
|
||||
margin-left: ${({ theme }) => theme.gridUnit / 2}px;
|
||||
color: ${({ theme }) => theme.colors.error.base};
|
||||
}
|
||||
|
||||
.helper {
|
||||
display: block;
|
||||
padding: ${({ theme }) => theme.gridUnit}px 0;
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.s - 1}px;
|
||||
text-align: left;
|
||||
}
|
||||
.ant-modal-title > h4 {
|
||||
font-weight: bold;
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledInputContainer = styled.div`
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 6}px;
|
||||
&.mb-0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&.mb-8 {
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
}
|
||||
|
||||
.control-label {
|
||||
color: ${({ theme }) => theme.colors.grayscale.dark1};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.s - 1}px;
|
||||
margin-bottom: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
}
|
||||
|
||||
&.extra-container {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
align-items: top;
|
||||
|
||||
label {
|
||||
display: flex;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
margin-top: ${({ theme }) => theme.gridUnit * 0.75}px;
|
||||
font-family: ${({ theme }) => theme.typography.families.sansSerif};
|
||||
font-size: ${({ theme }) => theme.typography.sizes.m}px;
|
||||
}
|
||||
|
||||
i {
|
||||
margin: 0 ${({ theme }) => theme.gridUnit}px;
|
||||
}
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
textarea {
|
||||
height: 160px;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
}
|
||||
|
||||
textarea,
|
||||
input[type='text'],
|
||||
input[type='number'] {
|
||||
padding: ${({ theme }) => theme.gridUnit * 1.5}px
|
||||
${({ theme }) => theme.gridUnit * 2}px;
|
||||
border-style: none;
|
||||
border: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||
border-radius: ${({ theme }) => theme.gridUnit}px;
|
||||
|
||||
&[name='name'] {
|
||||
flex: 0 1 auto;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
&[name='sqlalchemy_uri'] {
|
||||
margin-right: ${({ theme }) => theme.gridUnit * 3}px;
|
||||
}
|
||||
}
|
||||
&.expandable {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.25s;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 8}px;
|
||||
margin-bottom: 0;
|
||||
padding: 0;
|
||||
.control-label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
&.open {
|
||||
height: ${CTAS_CVAS_SCHEMA_FORM_HEIGHT}px;
|
||||
padding-right: ${({ theme }) => theme.gridUnit * 5}px;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledJsonEditor = styled(JsonEditor)`
|
||||
flex: 1 1 auto;
|
||||
border: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
|
||||
border-radius: ${({ theme }) => theme.gridUnit}px;
|
||||
`;
|
||||
|
||||
export const StyledExpandableForm = styled.div`
|
||||
padding-top: ${({ theme }) => theme.gridUnit}px;
|
||||
.input-container {
|
||||
padding-top: ${({ theme }) => theme.gridUnit}px;
|
||||
padding-bottom: ${({ theme }) => theme.gridUnit}px;
|
||||
}
|
||||
&.expandable {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
transition: height 0.25s;
|
||||
margin-left: ${({ theme }) => theme.gridUnit * 7}px;
|
||||
&.open {
|
||||
height: ${EXPOSE_IN_SQLLAB_FORM_HEIGHT}px;
|
||||
&.ctas-open {
|
||||
height: ${EXPOSE_ALL_FORM_HEIGHT}px;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const StyledRequiredTab = styled(Tabs.TabPane)`
|
||||
padding-left: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
padding-right: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
margin-top: ${({ theme }) => theme.gridUnit * 4}px;
|
||||
`;
|
Loading…
Reference in New Issue