mirror of
https://github.com/apache/superset.git
synced 2026-05-12 19:35:17 +00:00
refactor: Bootstrap to AntD - Form - iteration 4 (#14546)
This commit is contained in:
committed by
GitHub
parent
3eef38f309
commit
331eb10fb9
@@ -20,7 +20,6 @@
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
import { FormGroup } from 'react-bootstrap';
|
||||
|
||||
import AdhocFilter, {
|
||||
EXPRESSION_TYPES,
|
||||
@@ -86,7 +85,7 @@ function setup(overrides) {
|
||||
describe('AdhocFilterEditPopoverSimpleTabContent', () => {
|
||||
it('renders the simple tab form', () => {
|
||||
const { wrapper } = setup();
|
||||
expect(wrapper.find(FormGroup)).toHaveLength(3);
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it('passes the new adhocFilter to onChange after onSubjectChange', () => {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormGroup } from 'react-bootstrap';
|
||||
import { NativeSelect as Select } from 'src/components/Select';
|
||||
import { Input } from 'src/common/components';
|
||||
import { t, SupersetClient, styled } from '@superset-ui/core';
|
||||
@@ -346,80 +345,80 @@ export default class AdhocFilterEditPopoverSimpleTabContent extends React.Compon
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormGroup className="adhoc-filter-simple-column-dropdown">
|
||||
<Select
|
||||
{...this.selectProps}
|
||||
{...subjectSelectProps}
|
||||
name="filter-column"
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
>
|
||||
{columns.map(column => (
|
||||
<Select.Option
|
||||
value={column.id || column.optionName}
|
||||
filterBy={
|
||||
column.saved_metric_name || column.column_name || column.label
|
||||
}
|
||||
key={column.id || column.optionName}
|
||||
>
|
||||
{this.renderSubjectOptionLabel(column)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
<Select
|
||||
{...this.selectProps}
|
||||
{...operatorSelectProps}
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
name="filter-operator"
|
||||
>
|
||||
{OPERATORS_OPTIONS.filter(op =>
|
||||
this.isOperatorRelevant(op, subject),
|
||||
).map(option => (
|
||||
<Select.Option value={option} key={option}>
|
||||
{translateOperator(option)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</FormGroup>
|
||||
<FormGroup data-test="adhoc-filter-simple-value">
|
||||
{MULTI_OPERATORS.has(operator) ||
|
||||
this.state.suggestions.length > 0 ? (
|
||||
<SelectWithLabel
|
||||
name="filter-value"
|
||||
{...comparatorSelectProps}
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
onSearch={val => this.setState({ currentSuggestionSearch: val })}
|
||||
onSelect={this.clearSuggestionSearch}
|
||||
onBlur={this.clearSuggestionSearch}
|
||||
<Select
|
||||
css={theme => ({
|
||||
marginTop: theme.gridUnit * 4,
|
||||
marginBottom: theme.gridUnit * 4,
|
||||
})}
|
||||
{...this.selectProps}
|
||||
{...subjectSelectProps}
|
||||
name="filter-column"
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
>
|
||||
{columns.map(column => (
|
||||
<Select.Option
|
||||
value={column.id || column.optionName}
|
||||
filterBy={
|
||||
column.saved_metric_name || column.column_name || column.label
|
||||
}
|
||||
key={column.id || column.optionName}
|
||||
>
|
||||
{this.state.suggestions.map(suggestion => (
|
||||
<Select.Option value={suggestion} key={suggestion}>
|
||||
{suggestion}
|
||||
</Select.Option>
|
||||
))}
|
||||
{this.renderSubjectOptionLabel(column)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
<Select
|
||||
css={theme => ({ marginBottom: theme.gridUnit * 4 })}
|
||||
{...this.selectProps}
|
||||
{...operatorSelectProps}
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
name="filter-operator"
|
||||
>
|
||||
{OPERATORS_OPTIONS.filter(op =>
|
||||
this.isOperatorRelevant(op, subject),
|
||||
).map(option => (
|
||||
<Select.Option value={option} key={option}>
|
||||
{translateOperator(option)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
{MULTI_OPERATORS.has(operator) || this.state.suggestions.length > 0 ? (
|
||||
<SelectWithLabel
|
||||
data-test="adhoc-filter-simple-value"
|
||||
name="filter-value"
|
||||
{...comparatorSelectProps}
|
||||
getPopupContainer={triggerNode => triggerNode.parentNode}
|
||||
onSearch={val => this.setState({ currentSuggestionSearch: val })}
|
||||
onSelect={this.clearSuggestionSearch}
|
||||
onBlur={this.clearSuggestionSearch}
|
||||
>
|
||||
{this.state.suggestions.map(suggestion => (
|
||||
<Select.Option value={suggestion} key={suggestion}>
|
||||
{suggestion}
|
||||
</Select.Option>
|
||||
))}
|
||||
|
||||
{/* enable selecting an option not included in suggestions */}
|
||||
{currentSuggestionSearch &&
|
||||
!this.state.suggestions.some(
|
||||
suggestion => suggestion === currentSuggestionSearch,
|
||||
) && (
|
||||
<Select.Option value={currentSuggestionSearch}>
|
||||
{currentSuggestionSearch}
|
||||
</Select.Option>
|
||||
)}
|
||||
</SelectWithLabel>
|
||||
) : (
|
||||
<Input
|
||||
name="filter-value"
|
||||
ref={ref => this.focusComparator(ref, focusComparator)}
|
||||
onChange={this.onInputComparatorChange}
|
||||
value={comparator}
|
||||
placeholder={t('Filter value (case sensitive)')}
|
||||
disabled={DISABLE_INPUT_OPERATORS.includes(operator)}
|
||||
/>
|
||||
)}
|
||||
</FormGroup>
|
||||
{/* enable selecting an option not included in suggestions */}
|
||||
{currentSuggestionSearch &&
|
||||
!this.state.suggestions.some(
|
||||
suggestion => suggestion === currentSuggestionSearch,
|
||||
) && (
|
||||
<Select.Option value={currentSuggestionSearch}>
|
||||
{currentSuggestionSearch}
|
||||
</Select.Option>
|
||||
)}
|
||||
</SelectWithLabel>
|
||||
) : (
|
||||
<Input
|
||||
data-test="adhoc-filter-simple-value"
|
||||
name="filter-value"
|
||||
ref={ref => this.focusComparator(ref, focusComparator)}
|
||||
onChange={this.onInputComparatorChange}
|
||||
value={comparator}
|
||||
placeholder={t('Filter value (case sensitive)')}
|
||||
disabled={DISABLE_INPUT_OPERATORS.includes(operator)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
import React from 'react';
|
||||
import sinon from 'sinon';
|
||||
import { shallow } from 'enzyme';
|
||||
import { FormGroup } from 'react-bootstrap';
|
||||
|
||||
import AdhocFilter, {
|
||||
EXPRESSION_TYPES,
|
||||
@@ -50,7 +49,7 @@ function setup(overrides) {
|
||||
describe('AdhocFilterEditPopoverSqlTabContent', () => {
|
||||
it('renders the sql tab form', () => {
|
||||
const { wrapper } = setup();
|
||||
expect(wrapper.find(FormGroup)).toHaveLength(2);
|
||||
expect(wrapper).toExist();
|
||||
});
|
||||
|
||||
it('passes the new clause to onChange after onSqlExpressionClauseChange', () => {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormGroup } from 'react-bootstrap';
|
||||
import { NativeSelect as Select } from 'src/components/Select';
|
||||
import { t } from '@superset-ui/core';
|
||||
import { SQLEditor } from 'src/components/AsyncAceEditor';
|
||||
@@ -115,7 +114,7 @@ export default class AdhocFilterEditPopoverSqlTabContent extends React.Component
|
||||
|
||||
return (
|
||||
<span>
|
||||
<FormGroup className="filter-edit-clause-section">
|
||||
<div className="filter-edit-clause-section">
|
||||
<Select
|
||||
{...this.selectProps}
|
||||
{...clauseSelectProps}
|
||||
@@ -133,8 +132,8 @@ export default class AdhocFilterEditPopoverSqlTabContent extends React.Component
|
||||
<br />
|
||||
<strong>HAVING</strong> {t('Filters by metrics')}
|
||||
</span>
|
||||
</FormGroup>
|
||||
<FormGroup>
|
||||
</div>
|
||||
<div css={theme => ({ marginTop: theme.gridUnit * 4 })}>
|
||||
<SQLEditor
|
||||
ref={this.handleAceEditorRef}
|
||||
keywords={keywords}
|
||||
@@ -148,7 +147,7 @@ export default class AdhocFilterEditPopoverSqlTabContent extends React.Component
|
||||
className="filter-sql-editor"
|
||||
wrapEnabled
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormControl } from 'react-bootstrap';
|
||||
import { Input } from 'src/common/components';
|
||||
|
||||
const propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
@@ -38,7 +38,7 @@ const defaultProps = {
|
||||
|
||||
export default function HiddenControl(props) {
|
||||
// This wouldn't be necessary but might as well
|
||||
return <FormControl type="hidden" value={props.value} />;
|
||||
return <Input type="hidden" value={props.value} />;
|
||||
}
|
||||
|
||||
HiddenControl.propTypes = propTypes;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
import React from 'react';
|
||||
import { t } from '@superset-ui/core';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormControl } from 'react-bootstrap';
|
||||
import { Input } from 'src/common/components';
|
||||
import { Tooltip } from 'src/components/Tooltip';
|
||||
|
||||
const propTypes = {
|
||||
@@ -79,7 +79,7 @@ export default class AdhocMetricEditPopoverTitle extends React.Component {
|
||||
}
|
||||
|
||||
return this.state.isEditMode ? (
|
||||
<FormControl
|
||||
<Input
|
||||
className="metric-edit-popover-label-input"
|
||||
type="text"
|
||||
placeholder={title.label}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
*/
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { FormGroup, FormControl } from 'react-bootstrap';
|
||||
import { TextArea } from 'src/common/components';
|
||||
import { debounce } from 'lodash';
|
||||
import { t } from '@superset-ui/core';
|
||||
|
||||
@@ -99,16 +99,13 @@ export default class TextAreaControl extends React.Component {
|
||||
);
|
||||
}
|
||||
return (
|
||||
<FormGroup controlId="formControlsTextarea">
|
||||
<FormControl
|
||||
componentClass="textarea"
|
||||
placeholder={t('textarea')}
|
||||
onChange={this.onControlChange.bind(this)}
|
||||
value={value}
|
||||
disabled={this.props.readOnly}
|
||||
style={{ height: this.props.height }}
|
||||
/>
|
||||
</FormGroup>
|
||||
<TextArea
|
||||
placeholder={t('textarea')}
|
||||
onChange={this.onControlChange.bind(this)}
|
||||
value={value}
|
||||
disabled={this.props.readOnly}
|
||||
style={{ height: this.props.height }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
* under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import { FormGroup, FormControl, FormControlProps } from 'react-bootstrap';
|
||||
import { legacyValidateNumber, legacyValidateInteger } from '@superset-ui/core';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { FAST_DEBOUNCE } from 'src/constants';
|
||||
import ControlHeader from 'src/explore/components/ControlHeader';
|
||||
import { Input } from 'src/common/components';
|
||||
|
||||
type InputValueType = string | number;
|
||||
|
||||
@@ -39,13 +39,9 @@ export interface TextControlProps<T extends InputValueType = InputValueType> {
|
||||
}
|
||||
|
||||
export interface TextControlState {
|
||||
controlId: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const generateControlId = (controlId?: string) =>
|
||||
`formInlineName_${controlId ?? (Math.random() * 1000000).toFixed()}`;
|
||||
|
||||
const safeStringify = (value?: InputValueType | null) =>
|
||||
value == null ? '' : String(value);
|
||||
|
||||
@@ -58,9 +54,6 @@ export default class TextControl<
|
||||
super(props);
|
||||
this.initialValue = props.value;
|
||||
this.state = {
|
||||
// if there's no control id provided, generate a random
|
||||
// number to prevent rendering elements with same ids
|
||||
controlId: generateControlId(props.controlId),
|
||||
value: safeStringify(this.initialValue),
|
||||
};
|
||||
}
|
||||
@@ -94,8 +87,8 @@ export default class TextControl<
|
||||
this.onChange(inputValue);
|
||||
}, FAST_DEBOUNCE);
|
||||
|
||||
onChangeWrapper: FormControlProps['onChange'] = event => {
|
||||
const { value } = event.target as HTMLInputElement;
|
||||
onChangeWrapper = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const { value } = event.target;
|
||||
this.setState({ value }, () => {
|
||||
this.debouncedOnChange(value);
|
||||
});
|
||||
@@ -110,18 +103,16 @@ export default class TextControl<
|
||||
return (
|
||||
<div>
|
||||
<ControlHeader {...this.props} />
|
||||
<FormGroup controlId={this.state.controlId}>
|
||||
<FormControl
|
||||
type="text"
|
||||
data-test="inline-name"
|
||||
placeholder={this.props.placeholder}
|
||||
onChange={this.onChangeWrapper}
|
||||
onFocus={this.props.onFocus}
|
||||
value={value}
|
||||
disabled={this.props.disabled}
|
||||
aria-label={this.props.label}
|
||||
/>
|
||||
</FormGroup>
|
||||
<Input
|
||||
type="text"
|
||||
data-test="inline-name"
|
||||
placeholder={this.props.placeholder}
|
||||
onChange={this.onChangeWrapper}
|
||||
onFocus={this.props.onFocus}
|
||||
value={value}
|
||||
disabled={this.props.disabled}
|
||||
aria-label={this.props.label}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user