chore: wiring ControlLabel to a new FormLabel (#10388)

* chore: wiring ControlLabel to a new FormLabel

Creating new simple <FormLabel /> component and wiring all <label>
and react-bootstrap.ControlLabel towards it.

FormLabel becomes a pivotal point that can be altered to point to AntD
when we're ready.

* lint

* ViewportControl

* addressing comments
This commit is contained in:
Maxime Beauchemin 2020-07-23 00:27:22 -07:00 committed by GitHub
parent ea53916730
commit b438ba9ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 113 additions and 70 deletions

View File

@ -20,13 +20,13 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import {
FormGroup, FormGroup,
ControlLabel,
HelpBlock, HelpBlock,
FormControl, FormControl,
OverlayTrigger, OverlayTrigger,
Tooltip, Tooltip,
} from 'react-bootstrap'; } from 'react-bootstrap';
import FormLabel from 'src/components/FormLabel';
import './crud.less'; import './crud.less';
const propTypes = { const propTypes = {
@ -61,7 +61,7 @@ export default class Field extends React.PureComponent {
}); });
return ( return (
<FormGroup controlId={fieldKey}> <FormGroup controlId={fieldKey}>
<ControlLabel className="m-r-5"> <FormLabel className="m-r-5">
{label || fieldKey} {label || fieldKey}
{compact && descr && ( {compact && descr && (
<OverlayTrigger <OverlayTrigger
@ -75,7 +75,7 @@ export default class Field extends React.PureComponent {
<i className="fa fa-info-circle m-l-5" /> <i className="fa fa-info-circle m-l-5" />
</OverlayTrigger> </OverlayTrigger>
)} )}
</ControlLabel> </FormLabel>
{hookedControl} {hookedControl}
<FormControl.Feedback /> <FormControl.Feedback />
{!compact && descr && <HelpBlock>{descr}</HelpBlock>} {!compact && descr && <HelpBlock>{descr}</HelpBlock>}

View File

@ -21,8 +21,9 @@ import PropTypes from 'prop-types';
import { FormControl, FormGroup, Row, Col } from 'react-bootstrap'; import { FormControl, FormGroup, Row, Col } from 'react-bootstrap';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import Button from '../../components/Button'; import Button from 'src/components/Button';
import ModalTrigger from '../../components/ModalTrigger'; import FormLabel from 'src/components/FormLabel';
import ModalTrigger from 'src/components/ModalTrigger';
const propTypes = { const propTypes = {
query: PropTypes.object, query: PropTypes.object,
@ -91,9 +92,9 @@ class SaveQuery extends React.PureComponent {
<Row> <Row>
<Col md={12}> <Col md={12}>
<small> <small>
<label className="control-label" htmlFor="embed-height"> <FormLabel className="control-label" htmlFor="embed-height">
{t('Label')} {t('Label')}
</label> </FormLabel>
</small> </small>
<FormControl <FormControl
type="text" type="text"
@ -107,9 +108,9 @@ class SaveQuery extends React.PureComponent {
<Row> <Row>
<Col md={12}> <Col md={12}>
<small> <small>
<label className="control-label" htmlFor="embed-height"> <FormLabel className="control-label" htmlFor="embed-height">
{t('Description')} {t('Description')}
</label> </FormLabel>
</small> </small>
<FormControl <FormControl
componentClass="textarea" componentClass="textarea"

View File

@ -23,8 +23,9 @@ import chrono from 'chrono-node';
import { Col, FormControl, FormGroup, Row } from 'react-bootstrap'; import { Col, FormControl, FormGroup, Row } from 'react-bootstrap';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import Button from '../../components/Button'; import Button from 'src/components/Button';
import ModalTrigger from '../../components/ModalTrigger'; import ModalTrigger from 'src/components/ModalTrigger';
import FormLabel from 'src/components/FormLabel';
import './ScheduleQueryButton.less'; import './ScheduleQueryButton.less';
const validators = { const validators = {
@ -134,9 +135,9 @@ class ScheduleQueryButton extends React.PureComponent {
<FormGroup> <FormGroup>
<Row style={{ paddingBottom: '10px' }}> <Row style={{ paddingBottom: '10px' }}>
<Col md={12}> <Col md={12}>
<label className="control-label" htmlFor="embed-height"> <FormLabel className="control-label" htmlFor="embed-height">
{t('Label')} {t('Label')}
</label> </FormLabel>
<FormControl <FormControl
type="text" type="text"
placeholder={t('Label for your query')} placeholder={t('Label for your query')}
@ -147,9 +148,9 @@ class ScheduleQueryButton extends React.PureComponent {
</Row> </Row>
<Row style={{ paddingBottom: '10px' }}> <Row style={{ paddingBottom: '10px' }}>
<Col md={12}> <Col md={12}>
<label className="control-label" htmlFor="embed-height"> <FormLabel className="control-label" htmlFor="embed-height">
{t('Description')} {t('Description')}
</label> </FormLabel>
<FormControl <FormControl
componentClass="textarea" componentClass="textarea"
placeholder={t('Write a description for your query')} placeholder={t('Write a description for your query')}

View File

@ -21,6 +21,7 @@ import React, { useState } from 'react';
import styled from '@superset-ui/style'; import styled from '@superset-ui/style';
import { FormGroup, FormControl } from 'react-bootstrap'; import { FormGroup, FormControl } from 'react-bootstrap';
import Modal from 'src/components/Modal'; import Modal from 'src/components/Modal';
import FormLabel from 'src/components/FormLabel';
const StyleFormGroup = styled(FormGroup)` const StyleFormGroup = styled(FormGroup)`
padding-top: 8px; padding-top: 8px;
@ -66,14 +67,14 @@ export default function DeleteModal({
> >
<DescriptionContainer>{description}</DescriptionContainer> <DescriptionContainer>{description}</DescriptionContainer>
<StyleFormGroup> <StyleFormGroup>
<label htmlFor="delete">{t('type delete to confirm')}</label> <FormLabel htmlFor="delete">{t('type "delete" to confirm')}</FormLabel>
<FormControl <FormControl
id="delete" id="delete"
type="text" type="text"
bsSize="sm" bsSize="sm"
// @ts-ignore // @ts-ignore
onChange={(event: React.ChangeEvent<HTMLInputElement>) => onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
setDisableChange(event.target.value !== 'DELETE') setDisableChange(event.target.value.toUpperCase() !== 'DELETE')
} }
/> />
</StyleFormGroup> </StyleFormGroup>

View File

@ -0,0 +1,46 @@
/**
* 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/style';
import React, { ReactNode } from 'react';
import { ControlLabel } from 'react-bootstrap';
export type FormLabelProps = {
children: ReactNode;
htmlFor?: string;
required?: boolean;
};
export default function FormLabel({
children,
htmlFor,
required = false,
}: FormLabelProps) {
return (
<>
<ControlLabel htmlFor={htmlFor}>
{children}
{required && (
<span className="text-danger m-l-4">
<strong>*</strong>
</span>
)}
</ControlLabel>
</>
);
}

View File

@ -21,10 +21,12 @@ import styled from '@superset-ui/style';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import rison from 'rison'; import rison from 'rison';
import { Select, AsyncSelect } from 'src/components/Select'; import { Select, AsyncSelect } from 'src/components/Select';
import { ControlLabel, Label } from 'react-bootstrap'; import { Label } from 'react-bootstrap';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection'; import { SupersetClient } from '@superset-ui/connection';
import FormLabel from 'src/components/FormLabel';
import SupersetAsyncSelect from './AsyncSelect'; import SupersetAsyncSelect from './AsyncSelect';
import RefreshLabel from './RefreshLabel'; import RefreshLabel from './RefreshLabel';
import './TableSelector.less'; import './TableSelector.less';
@ -393,14 +395,14 @@ export default class TableSelector extends React.PureComponent {
renderSeeTableLabel() { renderSeeTableLabel() {
return ( return (
<div className="section"> <div className="section">
<ControlLabel> <FormLabel>
{t('See table schema')}{' '} {t('See table schema')}{' '}
{this.props.schema && ( {this.props.schema && (
<small> <small>
({this.state.tableOptions.length} in <i>{this.props.schema}</i>) ({this.state.tableOptions.length} in <i>{this.props.schema}</i>)
</small> </small>
)} )}
</ControlLabel> </FormLabel>
</div> </div>
); );
} }

View File

@ -20,6 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { isEmpty } from 'lodash'; import { isEmpty } from 'lodash';
import FormLabel from 'src/components/FormLabel';
const propTypes = { const propTypes = {
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
@ -41,7 +42,7 @@ export default function FilterIndicatorTooltip({
return ( return (
<div className="tooltip-item"> <div className="tooltip-item">
<div className="filter-content"> <div className="filter-content">
<label htmlFor={`filter-tooltip-${label}`}>{label}:</label> <FormLabel htmlFor={`filter-tooltip-${label}`}>{label}:</FormLabel>
<span> {displayValue}</span> <span> {displayValue}</span>
</div> </div>

View File

@ -25,10 +25,11 @@ import AceEditor from 'react-ace';
import rison from 'rison'; import rison from 'rison';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection'; import { SupersetClient } from '@superset-ui/connection';
import '../stylesheets/buttons.less';
import FormLabel from 'src/components/FormLabel';
import getClientErrorObject from '../../utils/getClientErrorObject'; import getClientErrorObject from '../../utils/getClientErrorObject';
import withToasts from '../../messageToasts/enhancers/withToasts'; import withToasts from '../../messageToasts/enhancers/withToasts';
import '../stylesheets/buttons.less';
const propTypes = { const propTypes = {
dashboardId: PropTypes.number.isRequired, dashboardId: PropTypes.number.isRequired,
@ -202,9 +203,7 @@ class PropertiesModal extends React.PureComponent {
</Row> </Row>
<Row> <Row>
<Col md={6}> <Col md={6}>
<label className="control-label" htmlFor="embed-height"> <FormLabel htmlFor="embed-height">{t('Title')}</FormLabel>
{t('Title')}
</label>
<FormControl <FormControl
name="dashboard_title" name="dashboard_title"
type="text" type="text"
@ -215,9 +214,7 @@ class PropertiesModal extends React.PureComponent {
/> />
</Col> </Col>
<Col md={6}> <Col md={6}>
<label className="control-label" htmlFor="embed-height"> <FormLabel htmlFor="embed-height">{t('URL Slug')}</FormLabel>
{t('URL Slug')}
</label>
<FormControl <FormControl
name="slug" name="slug"
type="text" type="text"
@ -234,9 +231,7 @@ class PropertiesModal extends React.PureComponent {
<Row> <Row>
<Col md={6}> <Col md={6}>
<h3 style={{ marginTop: '1em' }}>{t('Access')}</h3> <h3 style={{ marginTop: '1em' }}>{t('Access')}</h3>
<label className="control-label" htmlFor="owners"> <FormLabel htmlFor="owners">{t('Owners')}</FormLabel>
{t('Owners')}
</label>
<AsyncSelect <AsyncSelect
name="owners" name="owners"
isMulti isMulti
@ -274,9 +269,9 @@ class PropertiesModal extends React.PureComponent {
</h3> </h3>
{isAdvancedOpen && ( {isAdvancedOpen && (
<> <>
<label className="control-label" htmlFor="json_metadata"> <FormLabel htmlFor="json_metadata">
{t('JSON Metadata')} {t('JSON Metadata')}
</label> </FormLabel>
<AceEditor <AceEditor
mode="json" mode="json"
name="json_metadata" name="json_metadata"

View File

@ -20,7 +20,8 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import cx from 'classnames'; import cx from 'classnames';
import FilterBadgeIcon from '../../../components/FilterBadgeIcon'; import FormLabel from 'src/components/FormLabel';
import FilterBadgeIcon from 'src/components/FilterBadgeIcon';
const propTypes = { const propTypes = {
label: PropTypes.string.isRequired, label: PropTypes.string.isRequired,
@ -36,7 +37,7 @@ export default function FilterFieldItem({ label, colorCode, isSelected }) {
})} })}
> >
<FilterBadgeIcon colorCode={colorCode} /> <FilterBadgeIcon colorCode={colorCode} />
<label htmlFor={label}>{label}</label> <FormLabel htmlFor={label}>{label}</FormLabel>
</a> </a>
); );
} }

View File

@ -18,14 +18,7 @@
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { import { Button, FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
Button,
ControlLabel,
FormGroup,
Popover,
Tab,
Tabs,
} from 'react-bootstrap';
import Select from 'src/components/Select'; import Select from 'src/components/Select';
import ace from 'brace'; import ace from 'brace';
import AceEditor from 'react-ace'; import AceEditor from 'react-ace';
@ -35,6 +28,8 @@ import 'brace/ext/language_tools';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { ColumnOption } from '@superset-ui/chart-controls'; import { ColumnOption } from '@superset-ui/chart-controls';
import FormLabel from 'src/components/FormLabel';
import { AGGREGATES_OPTIONS } from '../constants'; import { AGGREGATES_OPTIONS } from '../constants';
import AdhocMetricEditPopoverTitle from './AdhocMetricEditPopoverTitle'; import AdhocMetricEditPopoverTitle from './AdhocMetricEditPopoverTitle';
import columnType from '../propTypes/columnType'; import columnType from '../propTypes/columnType';
@ -251,9 +246,9 @@ export default class AdhocMetricEditPopover extends React.Component {
title="Simple" title="Simple"
> >
<FormGroup> <FormGroup>
<ControlLabel> <FormLabel>
<strong>column</strong> <strong>column</strong>
</ControlLabel> </FormLabel>
<Select <Select
name="select-column" name="select-column"
{...this.selectProps} {...this.selectProps}
@ -261,9 +256,9 @@ export default class AdhocMetricEditPopover extends React.Component {
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<ControlLabel> <FormLabel>
<strong>aggregate</strong> <strong>aggregate</strong>
</ControlLabel> </FormLabel>
<Select <Select
name="select-aggregate" name="select-aggregate"
{...this.selectProps} {...this.selectProps}

View File

@ -19,8 +19,9 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { ControlLabel, OverlayTrigger, Tooltip } from 'react-bootstrap'; import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import FormLabel from 'src/components/FormLabel';
const propTypes = { const propTypes = {
name: PropTypes.string, name: PropTypes.string,
@ -83,7 +84,7 @@ export default class ControlHeader extends React.Component {
return ( return (
<div className="ControlHeader" data-test={`${this.props.name}-header`}> <div className="ControlHeader" data-test={`${this.props.name}-header`}>
<div className="pull-left"> <div className="pull-left">
<ControlLabel> <FormLabel>
{this.props.leftNode && <span>{this.props.leftNode}</span>} {this.props.leftNode && <span>{this.props.leftNode}</span>}
<span <span
role="button" role="button"
@ -133,7 +134,7 @@ export default class ControlHeader extends React.Component {
</span> </span>
)} )}
{this.renderOptionalIcons()} {this.renderOptionalIcons()}
</ControlLabel> </FormLabel>
</div> </div>
{this.props.rightNode && ( {this.props.rightNode && (
<div className="pull-right">{this.props.rightNode}</div> <div className="pull-right">{this.props.rightNode}</div>

View File

@ -21,7 +21,8 @@ import PropTypes from 'prop-types';
import { Popover, OverlayTrigger } from 'react-bootstrap'; import { Popover, OverlayTrigger } from 'react-bootstrap';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import CopyToClipboard from './../../components/CopyToClipboard'; import FormLabel from 'src/components/FormLabel';
import CopyToClipboard from 'src/components/CopyToClipboard';
import { getExploreLongUrl } from '../exploreUtils'; import { getExploreLongUrl } from '../exploreUtils';
const propTypes = { const propTypes = {
@ -97,9 +98,7 @@ export default class EmbedCodeButton extends React.Component {
<div className="col-md-6 col-sm-12"> <div className="col-md-6 col-sm-12">
<div className="form-group"> <div className="form-group">
<small> <small>
<label className="control-label" htmlFor="embed-height"> <FormLabel htmlFor="embed-height">{t('Height')}</FormLabel>
{t('Height')}
</label>
</small> </small>
<input <input
className="form-control input-sm" className="form-control input-sm"
@ -113,9 +112,7 @@ export default class EmbedCodeButton extends React.Component {
<div className="col-md-6 col-sm-12"> <div className="col-md-6 col-sm-12">
<div className="form-group"> <div className="form-group">
<small> <small>
<label className="control-label" htmlFor="embed-width"> <FormLabel htmlFor="embed-width">{t('Width')}</FormLabel>
{t('Width')}
</label>
</small> </small>
<input <input
className="form-control input-sm" className="form-control input-sm"

View File

@ -34,6 +34,7 @@ import rison from 'rison';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection'; import { SupersetClient } from '@superset-ui/connection';
import Chart from 'src/types/Chart'; import Chart from 'src/types/Chart';
import FormLabel from 'src/components/FormLabel';
import getClientErrorObject from '../../utils/getClientErrorObject'; import getClientErrorObject from '../../utils/getClientErrorObject';
export type Slice = { export type Slice = {
@ -182,9 +183,9 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
<Col md={6}> <Col md={6}>
<h3>{t('Basic Information')}</h3> <h3>{t('Basic Information')}</h3>
<FormGroup> <FormGroup>
<label className="control-label" htmlFor="name"> <FormLabel htmlFor="name" required>
{t('Name')} {t('Name')}
</label> </FormLabel>
<FormControl <FormControl
name="name" name="name"
type="text" type="text"
@ -197,9 +198,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
/> />
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<label className="control-label" htmlFor="description"> <FormLabel htmlFor="description">{t('Description')}</FormLabel>
{t('Description')}
</label>
<FormControl <FormControl
name="description" name="description"
type="text" type="text"
@ -222,9 +221,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
<Col md={6}> <Col md={6}>
<h3>{t('Configuration')}</h3> <h3>{t('Configuration')}</h3>
<FormGroup> <FormGroup>
<label className="control-label" htmlFor="cacheTimeout"> <FormLabel htmlFor="cacheTimeout">{t('Cache Timeout')}</FormLabel>
{t('Cache Timeout')}
</label>
<FormControl <FormControl
name="cacheTimeout" name="cacheTimeout"
type="text" type="text"
@ -243,9 +240,7 @@ function PropertiesModal({ slice, onHide, onSave }: InternalProps) {
</FormGroup> </FormGroup>
<h3 style={{ marginTop: '1em' }}>{t('Access')}</h3> <h3 style={{ marginTop: '1em' }}>{t('Access')}</h3>
<FormGroup> <FormGroup>
<label className="control-label" htmlFor="owners"> <FormLabel htmlFor="owners">{t('Owners')}</FormLabel>
{t('Owners')}
</label>
<AsyncSelect <AsyncSelect
isMulti isMulti
name="owners" name="owners"

View File

@ -21,6 +21,7 @@ import PropTypes from 'prop-types';
import { Label, Popover, OverlayTrigger } from 'react-bootstrap'; import { Label, Popover, OverlayTrigger } from 'react-bootstrap';
import { decimal2sexagesimal } from 'geolib'; import { decimal2sexagesimal } from 'geolib';
import FormLabel from 'src/components/FormLabel';
import TextControl from './TextControl'; import TextControl from './TextControl';
import ControlHeader from '../ControlHeader'; import ControlHeader from '../ControlHeader';
@ -67,7 +68,7 @@ export default class ViewportControl extends React.Component {
renderTextControl(ctrl) { renderTextControl(ctrl) {
return ( return (
<div key={ctrl}> <div key={ctrl}>
{ctrl} <FormLabel>{ctrl}</FormLabel>
<TextControl <TextControl
value={this.props.value[ctrl]} value={this.props.value[ctrl]}
onChange={this.onChange.bind(this, ctrl)} onChange={this.onChange.bind(this, ctrl)}

View File

@ -25,6 +25,8 @@ import { Button } from 'react-bootstrap';
import { t } from '@superset-ui/translation'; import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection'; import { SupersetClient } from '@superset-ui/connection';
import FormLabel from 'src/components/FormLabel';
import DateFilterControl from '../../explore/components/controls/DateFilterControl'; import DateFilterControl from '../../explore/components/controls/DateFilterControl';
import ControlRow from '../../explore/components/ControlRow'; import ControlRow from '../../explore/components/ControlRow';
import Control from '../../explore/components/Control'; import Control from '../../explore/components/Control';
@ -398,7 +400,7 @@ class FilterBox extends React.Component {
<div key={key} className="m-b-5 filter-container"> <div key={key} className="m-b-5 filter-container">
{this.renderFilterBadge(chartId, key, label)} {this.renderFilterBadge(chartId, key, label)}
<div> <div>
<label htmlFor={`LABEL-${key}`}>{label}</label> <FormLabel htmlFor={`LABEL-${key}`}>{label}</FormLabel>
{this.renderSelect(filterConfig)} {this.renderSelect(filterConfig)}
</div> </div>
</div> </div>

View File

@ -326,6 +326,10 @@ table.table-no-hover tr:hover {
margin-bottom: 10px; margin-bottom: 10px;
} }
.m-l-4 {
margin-left: 4px;
}
.m-l-5 { .m-l-5 {
margin-left: 5px; margin-left: 5px;
} }