mirror of
https://github.com/apache/superset.git
synced 2024-09-06 13:57:40 -04:00
refactor: Bootstrap to AntD - Form - iteration 3 (#14502)
This commit is contained in:
parent
4f000cc8d1
commit
79ff96269b
@ -20,7 +20,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { FormGroup } from 'react-bootstrap';
|
import { FormItem } from 'src/components/Form';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
import { AGGREGATES } from 'src/explore/constants';
|
import { AGGREGATES } from 'src/explore/constants';
|
||||||
@ -67,7 +67,7 @@ function setup(overrides) {
|
|||||||
describe('AdhocMetricEditPopover', () => {
|
describe('AdhocMetricEditPopover', () => {
|
||||||
it('renders a popover with edit metric form contents', () => {
|
it('renders a popover with edit metric form contents', () => {
|
||||||
const { wrapper } = setup();
|
const { wrapper } = setup();
|
||||||
expect(wrapper.find(FormGroup)).toHaveLength(4);
|
expect(wrapper.find(FormItem)).toHaveLength(3);
|
||||||
expect(wrapper.find(Button)).toHaveLength(2);
|
expect(wrapper.find(Button)).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormControl } from 'react-bootstrap';
|
|
||||||
import sinon from 'sinon';
|
import sinon from 'sinon';
|
||||||
import { styledMount as mount } from 'spec/helpers/theming';
|
import { styledMount as mount } from 'spec/helpers/theming';
|
||||||
import BoundsControl from 'src/explore/components/controls/BoundsControl';
|
import BoundsControl from 'src/explore/components/controls/BoundsControl';
|
||||||
|
import { Input } from 'src/common/components';
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
name: 'y_axis_bounds',
|
name: 'y_axis_bounds',
|
||||||
@ -35,13 +35,13 @@ describe('BoundsControl', () => {
|
|||||||
wrapper = mount(<BoundsControl {...defaultProps} />);
|
wrapper = mount(<BoundsControl {...defaultProps} />);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders two FormControls', () => {
|
it('renders two Input', () => {
|
||||||
expect(wrapper.find(FormControl)).toHaveLength(2);
|
expect(wrapper.find(Input)).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('errors on non-numeric', () => {
|
it('errors on non-numeric', () => {
|
||||||
wrapper
|
wrapper
|
||||||
.find(FormControl)
|
.find(Input)
|
||||||
.first()
|
.first()
|
||||||
.simulate('change', { target: { value: 's' } });
|
.simulate('change', { target: { value: 's' } });
|
||||||
expect(defaultProps.onChange.calledWith([null, null])).toBe(true);
|
expect(defaultProps.onChange.calledWith([null, null])).toBe(true);
|
||||||
@ -51,11 +51,11 @@ describe('BoundsControl', () => {
|
|||||||
});
|
});
|
||||||
it('casts to numeric', () => {
|
it('casts to numeric', () => {
|
||||||
wrapper
|
wrapper
|
||||||
.find(FormControl)
|
.find(Input)
|
||||||
.first()
|
.first()
|
||||||
.simulate('change', { target: { value: '1' } });
|
.simulate('change', { target: { value: '1' } });
|
||||||
wrapper
|
wrapper
|
||||||
.find(FormControl)
|
.find(Input)
|
||||||
.last()
|
.last()
|
||||||
.simulate('change', { target: { value: '5' } });
|
.simulate('change', { target: { value: '5' } });
|
||||||
expect(defaultProps.onChange.calledWith([1, 5])).toBe(true);
|
expect(defaultProps.onChange.calledWith([1, 5])).toBe(true);
|
||||||
|
@ -17,12 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormControl } from 'react-bootstrap';
|
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
import SaveQuery from 'src/SqlLab/components/SaveQuery';
|
import SaveQuery from 'src/SqlLab/components/SaveQuery';
|
||||||
import Modal from 'src/components/Modal';
|
import Modal from 'src/components/Modal';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
|
import { FormItem } from 'src/components/Form';
|
||||||
|
|
||||||
describe('SavedQuery', () => {
|
describe('SavedQuery', () => {
|
||||||
const mockedProps = {
|
const mockedProps = {
|
||||||
@ -52,11 +52,11 @@ describe('SavedQuery', () => {
|
|||||||
|
|
||||||
expect(modal.find('[data-test="cancel-query"]')).toHaveLength(1);
|
expect(modal.find('[data-test="cancel-query"]')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
it('has 2 FormControls', () => {
|
it('has 2 FormItem', () => {
|
||||||
const wrapper = shallow(<SaveQuery {...mockedProps} />);
|
const wrapper = shallow(<SaveQuery {...mockedProps} />);
|
||||||
const modal = wrapper.find(Modal);
|
const modal = wrapper.find(Modal);
|
||||||
|
|
||||||
expect(modal.find(FormControl)).toHaveLength(2);
|
expect(modal.find(FormItem)).toHaveLength(2);
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line jest/no-disabled-tests
|
// eslint-disable-next-line jest/no-disabled-tests
|
||||||
it.skip('has a save button if this is a new query', () => {
|
it.skip('has a save button if this is a new query', () => {
|
||||||
|
@ -17,12 +17,10 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Row, Col } from 'src/common/components';
|
import { Row, Col, Input, TextArea } from 'src/common/components';
|
||||||
import { FormControl, FormGroup } from 'react-bootstrap';
|
|
||||||
import { t, supersetTheme, styled } from '@superset-ui/core';
|
import { t, supersetTheme, styled } from '@superset-ui/core';
|
||||||
|
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
import { FormLabel } from 'src/components/Form';
|
import { Form, FormItem } from 'src/components/Form';
|
||||||
import Modal from 'src/components/Modal';
|
import Modal from 'src/components/Modal';
|
||||||
import Icon from 'src/components/Icon';
|
import Icon from 'src/components/Icon';
|
||||||
|
|
||||||
@ -100,12 +98,12 @@ export default function SaveQuery({
|
|||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onLabelChange = (e: React.FormEvent<FormControl>) => {
|
const onLabelChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
setLabel((e.target as HTMLInputElement).value);
|
setLabel(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDescriptionChange = (e: React.FormEvent<FormControl>) => {
|
const onDescriptionChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
setDescription((e.target as HTMLInputElement).value);
|
setDescription(e.target.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleSave = () => {
|
const toggleSave = () => {
|
||||||
@ -113,27 +111,24 @@ export default function SaveQuery({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderModalBody = () => (
|
const renderModalBody = () => (
|
||||||
<FormGroup bsSize="small">
|
<Form layout="vertical">
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={24}>
|
<Col xs={24}>
|
||||||
<small>
|
<FormItem label={t('Name')}>
|
||||||
<FormLabel htmlFor="embed-height">{t('Name')}</FormLabel>
|
<Input type="text" value={label} onChange={onLabelChange} />
|
||||||
</small>
|
</FormItem>
|
||||||
<FormControl type="text" value={label} onChange={onLabelChange} />
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<br />
|
<br />
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={24}>
|
<Col xs={24}>
|
||||||
<small>
|
<FormItem label={t('Description')}>
|
||||||
<FormLabel htmlFor="embed-height">{t('Description')}</FormLabel>
|
<TextArea
|
||||||
</small>
|
rows={4}
|
||||||
<FormControl
|
value={description}
|
||||||
rows={5}
|
onChange={onDescriptionChange}
|
||||||
componentClass="textarea"
|
/>
|
||||||
value={description}
|
</FormItem>
|
||||||
onChange={onDescriptionChange}
|
|
||||||
/>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
{saveQueryWarning && (
|
{saveQueryWarning && (
|
||||||
@ -149,7 +144,7 @@ export default function SaveQuery({
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -17,13 +17,12 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { FunctionComponent, useState } from 'react';
|
import React, { FunctionComponent, useState } from 'react';
|
||||||
import Form, { FormProps, FormValidation } from 'react-jsonschema-form';
|
import SchemaForm, { FormProps, FormValidation } from 'react-jsonschema-form';
|
||||||
import { Row, Col } from 'src/common/components';
|
import { Row, Col, Input, TextArea } from 'src/common/components';
|
||||||
import { FormControl, FormGroup } from 'react-bootstrap';
|
|
||||||
import { t, styled } from '@superset-ui/core';
|
import { t, styled } from '@superset-ui/core';
|
||||||
import * as chrono from 'chrono-node';
|
import * as chrono from 'chrono-node';
|
||||||
import ModalTrigger from 'src/components/ModalTrigger';
|
import ModalTrigger from 'src/components/ModalTrigger';
|
||||||
import { FormLabel } from 'src/components/Form';
|
import { Form, FormItem } from 'src/components/Form';
|
||||||
import './ScheduleQueryButton.less';
|
import './ScheduleQueryButton.less';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
|
|
||||||
@ -139,42 +138,52 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const renderModalBody = () => (
|
const renderModalBody = () => (
|
||||||
<FormGroup>
|
<Form layout="vertical">
|
||||||
<StyledRow>
|
<StyledRow>
|
||||||
<Col xs={24}>
|
<Col xs={24}>
|
||||||
<FormLabel className="control-label" htmlFor="embed-height">
|
<FormItem label={t('Label')}>
|
||||||
{t('Label')}
|
<Input
|
||||||
</FormLabel>
|
type="text"
|
||||||
<FormControl
|
placeholder={t('Label for your query')}
|
||||||
type="text"
|
value={label}
|
||||||
placeholder={t('Label for your query')}
|
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
|
||||||
value={label}
|
setLabel(event.target.value)
|
||||||
onChange={(event: any) => setLabel(event.target?.value)}
|
}
|
||||||
/>
|
/>
|
||||||
|
</FormItem>
|
||||||
</Col>
|
</Col>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
<StyledRow>
|
<StyledRow>
|
||||||
<Col xs={24}>
|
<Col xs={24}>
|
||||||
<FormLabel className="control-label" htmlFor="embed-height">
|
<FormItem label={t('Description')}>
|
||||||
{t('Description')}
|
<TextArea
|
||||||
</FormLabel>
|
rows={4}
|
||||||
<FormControl
|
placeholder={t('Write a description for your query')}
|
||||||
componentClass="textarea"
|
value={description}
|
||||||
placeholder={t('Write a description for your query')}
|
onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>
|
||||||
value={description}
|
setDescription(event.target.value)
|
||||||
onChange={(event: any) => setDescription(event.target?.value)}
|
}
|
||||||
/>
|
/>
|
||||||
|
</FormItem>
|
||||||
</Col>
|
</Col>
|
||||||
</StyledRow>
|
</StyledRow>
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={24}>
|
<Col xs={24}>
|
||||||
<div className="json-schema">
|
<div className="json-schema">
|
||||||
<Form
|
<SchemaForm
|
||||||
schema={getJSONSchema()}
|
schema={getJSONSchema()}
|
||||||
uiSchema={getUISchema}
|
uiSchema={getUISchema}
|
||||||
onSubmit={onScheduleSubmit}
|
onSubmit={onScheduleSubmit}
|
||||||
validate={getValidator()}
|
validate={getValidator()}
|
||||||
/>
|
>
|
||||||
|
<Button
|
||||||
|
buttonStyle="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
css={{ float: 'right' }}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</SchemaForm>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -185,7 +194,7 @@ const ScheduleQueryButton: FunctionComponent<ScheduleQueryButtonProps> = ({
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
)}
|
)}
|
||||||
</FormGroup>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -89,11 +89,13 @@ export const Menu = Object.assign(AntdMenu, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const Input = styled(AntdInput)`
|
export const Input = styled(AntdInput)`
|
||||||
&[type='text'],
|
border: 1px solid ${({ theme }) => theme.colors.secondary.light3};
|
||||||
&[type='textarea'] {
|
border-radius: ${({ theme }) => theme.borderRadius}px;
|
||||||
border: 1px solid ${({ theme }) => theme.colors.secondary.light3};
|
`;
|
||||||
border-radius: ${({ theme }) => theme.borderRadius}px;
|
|
||||||
}
|
export const TextArea = styled(AntdInput.TextArea)`
|
||||||
|
border: 1px solid ${({ theme }) => theme.colors.secondary.light3};
|
||||||
|
border-radius: ${({ theme }) => theme.borderRadius}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const NoAnimationDropdown = (props: DropDownProps) => (
|
export const NoAnimationDropdown = (props: DropDownProps) => (
|
||||||
|
@ -21,23 +21,28 @@ import Form, { FormItemProps } from 'antd/lib/form';
|
|||||||
import { styled } from '@superset-ui/core';
|
import { styled } from '@superset-ui/core';
|
||||||
|
|
||||||
const StyledItem = styled(Form.Item)`
|
const StyledItem = styled(Form.Item)`
|
||||||
.ant-form-item-label > label {
|
${({ theme }) => `
|
||||||
text-transform: uppercase;
|
.ant-form-item-label {
|
||||||
font-size: ${({ theme }) => theme.typography.sizes.s}px;
|
padding-bottom: ${theme.gridUnit}px;
|
||||||
color: ${({ theme }) => theme.colors.grayscale.base};
|
& > label {
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: ${theme.typography.sizes.s}px;
|
||||||
|
color: ${theme.colors.grayscale.base};
|
||||||
|
|
||||||
&.ant-form-item-required:not(.ant-form-item-required-mark-optional) {
|
&.ant-form-item-required:not(.ant-form-item-required-mark-optional) {
|
||||||
&::before {
|
&::before {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
&::after {
|
&::after {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: ${({ theme }) => theme.colors.error.base};
|
color: ${theme.colors.error.base};
|
||||||
font-size: ${({ theme }) => theme.typography.sizes.m}px;
|
font-size: ${theme.typography.sizes.m}px;
|
||||||
content: '*';
|
content: '*';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
`}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function FormItem(props: FormItemProps) {
|
export default function FormItem(props: FormItemProps) {
|
||||||
|
@ -350,7 +350,7 @@ class PropertiesModal extends React.PureComponent {
|
|||||||
<ColorSchemeControlWrapper
|
<ColorSchemeControlWrapper
|
||||||
onChange={this.onColorSchemeChange}
|
onChange={this.onColorSchemeChange}
|
||||||
colorScheme={values.colorScheme}
|
colorScheme={values.colorScheme}
|
||||||
labelMargin={8}
|
labelMargin={4}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -413,7 +413,7 @@ class PropertiesModal extends React.PureComponent {
|
|||||||
<ColorSchemeControlWrapper
|
<ColorSchemeControlWrapper
|
||||||
onChange={this.onColorSchemeChange}
|
onChange={this.onColorSchemeChange}
|
||||||
colorScheme={values.colorScheme}
|
colorScheme={values.colorScheme}
|
||||||
labelMargin={8}
|
labelMargin={4}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -18,10 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { styled, t } from '@superset-ui/core';
|
||||||
import { FormControl } from 'react-bootstrap';
|
|
||||||
import { Column } from 'react-table';
|
import { Column } from 'react-table';
|
||||||
import debounce from 'lodash/debounce';
|
import debounce from 'lodash/debounce';
|
||||||
|
import { Input } from 'src/common/components';
|
||||||
import {
|
import {
|
||||||
BOOL_FALSE_DISPLAY,
|
BOOL_FALSE_DISPLAY,
|
||||||
BOOL_TRUE_DISPLAY,
|
BOOL_TRUE_DISPLAY,
|
||||||
@ -73,9 +72,8 @@ export const FilterInput = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const debouncedChangeHandler = debounce(onChangeHandler, SLOW_DEBOUNCE);
|
const debouncedChangeHandler = debounce(onChangeHandler, SLOW_DEBOUNCE);
|
||||||
return (
|
return (
|
||||||
<FormControl
|
<Input
|
||||||
placeholder={t('Search')}
|
placeholder={t('Search')}
|
||||||
bsSize="sm"
|
|
||||||
onChange={(event: any) => {
|
onChange={(event: any) => {
|
||||||
const filterText = event.target.value;
|
const filterText = event.target.value;
|
||||||
debouncedChangeHandler(filterText);
|
debouncedChangeHandler(filterText);
|
||||||
|
@ -18,8 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Row, Col } from 'src/common/components';
|
import { Row, Col, Input } from 'src/common/components';
|
||||||
import { FormGroup, FormControl } from 'react-bootstrap';
|
|
||||||
import { t } from '@superset-ui/core';
|
import { t } from '@superset-ui/core';
|
||||||
import ControlHeader from '../ControlHeader';
|
import ControlHeader from '../ControlHeader';
|
||||||
|
|
||||||
@ -87,28 +86,26 @@ export default class BoundsControl extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ControlHeader {...this.props} />
|
<ControlHeader {...this.props} />
|
||||||
<FormGroup bsSize="small">
|
<Row gutter={16}>
|
||||||
<Row gutter={16}>
|
<Col xs={12}>
|
||||||
<Col xs={12}>
|
<Input
|
||||||
<FormControl
|
data-test="min-bound"
|
||||||
data-test="min-bound"
|
type="text"
|
||||||
type="text"
|
placeholder={t('Min')}
|
||||||
placeholder={t('Min')}
|
onChange={this.onMinChange}
|
||||||
onChange={this.onMinChange}
|
value={this.state.minMax[0]}
|
||||||
value={this.state.minMax[0]}
|
/>
|
||||||
/>
|
</Col>
|
||||||
</Col>
|
<Col xs={12}>
|
||||||
<Col xs={12}>
|
<Input
|
||||||
<FormControl
|
type="text"
|
||||||
type="text"
|
data-test="max-bound"
|
||||||
data-test="max-bound"
|
placeholder={t('Max')}
|
||||||
placeholder={t('Max')}
|
onChange={this.onMaxChange}
|
||||||
onChange={this.onMaxChange}
|
value={this.state.minMax[1]}
|
||||||
value={this.state.minMax[1]}
|
/>
|
||||||
/>
|
</Col>
|
||||||
</Col>
|
</Row>
|
||||||
</Row>
|
|
||||||
</FormGroup>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ test('Should switch to tab:Custom SQL', () => {
|
|||||||
).toBeInTheDocument();
|
).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should render "Custom SQL" tab correctly', () => {
|
test('Should render "Custom SQL" tab correctly', async () => {
|
||||||
const props = createProps();
|
const props = createProps();
|
||||||
props.getCurrentTab.mockImplementation(tab => {
|
props.getCurrentTab.mockImplementation(tab => {
|
||||||
props.adhocMetric.expressionType = tab;
|
props.adhocMetric.expressionType = tab;
|
||||||
@ -180,5 +180,5 @@ test('Should render "Custom SQL" tab correctly', () => {
|
|||||||
const tab = screen.getByRole('tab', { name: 'Custom SQL' }).parentElement!;
|
const tab = screen.getByRole('tab', { name: 'Custom SQL' }).parentElement!;
|
||||||
userEvent.click(tab);
|
userEvent.click(tab);
|
||||||
|
|
||||||
expect(screen.getByTestId('sql-editor')).toBeVisible();
|
expect(await screen.findByRole('textbox')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
@ -19,13 +19,12 @@
|
|||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { FormGroup } from 'react-bootstrap';
|
|
||||||
import Tabs from 'src/components/Tabs';
|
import Tabs from 'src/components/Tabs';
|
||||||
import Button from 'src/components/Button';
|
import Button from 'src/components/Button';
|
||||||
import { NativeSelect as Select } from 'src/components/Select';
|
import { NativeSelect as Select } from 'src/components/Select';
|
||||||
import { t, styled } from '@superset-ui/core';
|
import { t, styled } from '@superset-ui/core';
|
||||||
|
|
||||||
import { FormLabel } from 'src/components/Form';
|
import { Form, FormItem } from 'src/components/Form';
|
||||||
import { SQLEditor } from 'src/components/AsyncAceEditor';
|
import { SQLEditor } from 'src/components/AsyncAceEditor';
|
||||||
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
|
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
|
||||||
import { noOp } from 'src/utils/common';
|
import { noOp } from 'src/utils/common';
|
||||||
@ -337,7 +336,8 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
savedMetric?.metric_name !== propsSavedMetric?.metric_name);
|
savedMetric?.metric_name !== propsSavedMetric?.metric_name);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Form
|
||||||
|
layout="vertical"
|
||||||
id="metrics-edit-popover"
|
id="metrics-edit-popover"
|
||||||
data-test="metrics-edit-popover"
|
data-test="metrics-edit-popover"
|
||||||
{...popoverProps}
|
{...popoverProps}
|
||||||
@ -352,10 +352,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
allowOverflow
|
allowOverflow
|
||||||
>
|
>
|
||||||
<Tabs.TabPane key={SAVED_TAB_KEY} tab={t('Saved')}>
|
<Tabs.TabPane key={SAVED_TAB_KEY} tab={t('Saved')}>
|
||||||
<FormGroup>
|
<FormItem label={t('Saved metric')}>
|
||||||
<FormLabel>
|
|
||||||
<strong>{t('Saved metric')}</strong>
|
|
||||||
</FormLabel>
|
|
||||||
<StyledSelect
|
<StyledSelect
|
||||||
{...savedSelectProps}
|
{...savedSelectProps}
|
||||||
name="select-saved"
|
name="select-saved"
|
||||||
@ -374,13 +371,10 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</StyledSelect>
|
</StyledSelect>
|
||||||
</FormGroup>
|
</FormItem>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane key={EXPRESSION_TYPES.SIMPLE} tab={t('Simple')}>
|
<Tabs.TabPane key={EXPRESSION_TYPES.SIMPLE} tab={t('Simple')}>
|
||||||
<FormGroup>
|
<FormItem label={t('column')}>
|
||||||
<FormLabel>
|
|
||||||
<strong>{t('column')}</strong>
|
|
||||||
</FormLabel>
|
|
||||||
<Select
|
<Select
|
||||||
{...columnSelectProps}
|
{...columnSelectProps}
|
||||||
name="select-column"
|
name="select-column"
|
||||||
@ -396,11 +390,8 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormGroup>
|
</FormItem>
|
||||||
<FormGroup>
|
<FormItem label={t('aggregate')}>
|
||||||
<FormLabel>
|
|
||||||
<strong>{t('aggregate')}</strong>
|
|
||||||
</FormLabel>
|
|
||||||
<Select
|
<Select
|
||||||
{...aggregateSelectProps}
|
{...aggregateSelectProps}
|
||||||
name="select-aggregate"
|
name="select-aggregate"
|
||||||
@ -412,7 +403,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormGroup>
|
</FormItem>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane
|
<Tabs.TabPane
|
||||||
key={EXPRESSION_TYPES.SQL}
|
key={EXPRESSION_TYPES.SQL}
|
||||||
@ -420,24 +411,23 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
data-test="adhoc-metric-edit-tab#custom"
|
data-test="adhoc-metric-edit-tab#custom"
|
||||||
>
|
>
|
||||||
{this.props.datasourceType !== 'druid' ? (
|
{this.props.datasourceType !== 'druid' ? (
|
||||||
<FormGroup data-test="sql-editor">
|
<SQLEditor
|
||||||
<SQLEditor
|
data-test="sql-editor"
|
||||||
showLoadingForImport
|
showLoadingForImport
|
||||||
ref={this.handleAceEditorRef}
|
ref={this.handleAceEditorRef}
|
||||||
keywords={keywords}
|
keywords={keywords}
|
||||||
height={`${this.state.height - 80}px`}
|
height={`${this.state.height - 80}px`}
|
||||||
onChange={this.onSqlExpressionChange}
|
onChange={this.onSqlExpressionChange}
|
||||||
width="100%"
|
width="100%"
|
||||||
showGutter={false}
|
showGutter={false}
|
||||||
value={
|
value={
|
||||||
adhocMetric.sqlExpression || adhocMetric.translateToSql()
|
adhocMetric.sqlExpression || adhocMetric.translateToSql()
|
||||||
}
|
}
|
||||||
editorProps={{ $blockScrolling: true }}
|
editorProps={{ $blockScrolling: true }}
|
||||||
enableLiveAutocompletion
|
enableLiveAutocompletion
|
||||||
className="filter-sql-editor"
|
className="adhoc-filter-sql-editor"
|
||||||
wrapEnabled
|
wrapEnabled
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
|
||||||
) : (
|
) : (
|
||||||
<div className="custom-sql-disabled-message">
|
<div className="custom-sql-disabled-message">
|
||||||
Custom SQL Metrics are not available on druid datasources
|
Custom SQL Metrics are not available on druid datasources
|
||||||
@ -474,7 +464,7 @@ export default class AdhocMetricEditPopover extends React.PureComponent {
|
|||||||
className="fa fa-expand edit-popover-resize text-muted"
|
className="fa fa-expand edit-popover-resize text-muted"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,11 +18,10 @@
|
|||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Row, Col } from 'src/common/components';
|
import { Row, Col, Input } from 'src/common/components';
|
||||||
import { FormControl } from 'react-bootstrap';
|
|
||||||
import Popover from 'src/components/Popover';
|
import Popover from 'src/components/Popover';
|
||||||
import Select from 'src/components/Select';
|
import Select from 'src/components/Select';
|
||||||
import { t } from '@superset-ui/core';
|
import { t, styled } from '@superset-ui/core';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
import BoundsControl from '../BoundsControl';
|
import BoundsControl from '../BoundsControl';
|
||||||
@ -75,6 +74,20 @@ const colTypeOptions = [
|
|||||||
{ value: 'avg', label: 'Period average' },
|
{ value: 'avg', label: 'Period average' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const StyledRow = styled(Row)`
|
||||||
|
margin-top: ${({ theme }) => theme.gridUnit * 2}px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledCol = styled(Col)`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const StyledTooltip = styled(InfoTooltipWithTrigger)`
|
||||||
|
margin-left: ${({ theme }) => theme.gridUnit}px;
|
||||||
|
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||||
|
`;
|
||||||
|
|
||||||
export default class TimeSeriesColumnControl extends React.Component {
|
export default class TimeSeriesColumnControl extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -128,19 +141,15 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
|
|
||||||
formRow(label, tooltip, ttLabel, control) {
|
formRow(label, tooltip, ttLabel, control) {
|
||||||
return (
|
return (
|
||||||
<Row style={{ marginTop: '5px' }}>
|
<StyledRow>
|
||||||
<Col xs={24} md={10}>
|
<StyledCol xs={24} md={10}>
|
||||||
{`${label} `}
|
{label}
|
||||||
<InfoTooltipWithTrigger
|
<StyledTooltip placement="top" tooltip={tooltip} label={ttLabel} />
|
||||||
placement="top"
|
</StyledCol>
|
||||||
tooltip={tooltip}
|
<StyledCol xs={24} md={14}>
|
||||||
label={ttLabel}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col xs={24} md={14}>
|
|
||||||
{control}
|
{control}
|
||||||
</Col>
|
</StyledCol>
|
||||||
</Row>
|
</StyledRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,10 +160,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Label',
|
'Label',
|
||||||
'The column header label',
|
'The column header label',
|
||||||
'time-lag',
|
'time-lag',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.label}
|
value={this.state.label}
|
||||||
onChange={this.onTextInputChange.bind(this, 'label')}
|
onChange={this.onTextInputChange.bind(this, 'label')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Label"
|
placeholder="Label"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -162,10 +170,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Tooltip',
|
'Tooltip',
|
||||||
'Column header tooltip',
|
'Column header tooltip',
|
||||||
'col-tooltip',
|
'col-tooltip',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.tooltip}
|
value={this.state.tooltip}
|
||||||
onChange={this.onTextInputChange.bind(this, 'tooltip')}
|
onChange={this.onTextInputChange.bind(this, 'tooltip')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Tooltip"
|
placeholder="Tooltip"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -186,10 +193,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Width',
|
'Width',
|
||||||
'Width of the sparkline',
|
'Width of the sparkline',
|
||||||
'spark-width',
|
'spark-width',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.width}
|
value={this.state.width}
|
||||||
onChange={this.onTextInputChange.bind(this, 'width')}
|
onChange={this.onTextInputChange.bind(this, 'width')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Width"
|
placeholder="Width"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -198,10 +204,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Height',
|
'Height',
|
||||||
'Height of the sparkline',
|
'Height of the sparkline',
|
||||||
'spark-width',
|
'spark-width',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.height}
|
value={this.state.height}
|
||||||
onChange={this.onTextInputChange.bind(this, 'height')}
|
onChange={this.onTextInputChange.bind(this, 'height')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Height"
|
placeholder="Height"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -210,10 +215,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Time lag',
|
'Time lag',
|
||||||
'Number of periods to compare against',
|
'Number of periods to compare against',
|
||||||
'time-lag',
|
'time-lag',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.timeLag}
|
value={this.state.timeLag}
|
||||||
onChange={this.onTextInputChange.bind(this, 'timeLag')}
|
onChange={this.onTextInputChange.bind(this, 'timeLag')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Time Lag"
|
placeholder="Time Lag"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -222,10 +226,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Time ratio',
|
'Time ratio',
|
||||||
'Number of periods to ratio against',
|
'Number of periods to ratio against',
|
||||||
'time-ratio',
|
'time-ratio',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.timeRatio}
|
value={this.state.timeRatio}
|
||||||
onChange={this.onTextInputChange.bind(this, 'timeRatio')}
|
onChange={this.onTextInputChange.bind(this, 'timeRatio')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Time Ratio"
|
placeholder="Time Ratio"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -277,10 +280,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Number format',
|
'Number format',
|
||||||
'Optional d3 number format string',
|
'Optional d3 number format string',
|
||||||
'd3-format',
|
'd3-format',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.d3format}
|
value={this.state.d3format}
|
||||||
onChange={this.onTextInputChange.bind(this, 'd3format')}
|
onChange={this.onTextInputChange.bind(this, 'd3format')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Number format string"
|
placeholder="Number format string"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
@ -289,10 +291,9 @@ export default class TimeSeriesColumnControl extends React.Component {
|
|||||||
'Date format',
|
'Date format',
|
||||||
'Optional d3 date format string',
|
'Optional d3 date format string',
|
||||||
'date-format',
|
'date-format',
|
||||||
<FormControl
|
<Input
|
||||||
value={this.state.dateFormat}
|
value={this.state.dateFormat}
|
||||||
onChange={this.onTextInputChange.bind(this, 'dateFormat')}
|
onChange={this.onTextInputChange.bind(this, 'dateFormat')}
|
||||||
bsSize="small"
|
|
||||||
placeholder="Date format string"
|
placeholder="Date format string"
|
||||||
/>,
|
/>,
|
||||||
)}
|
)}
|
||||||
|
Loading…
Reference in New Issue
Block a user