refactor: Replace usages of Popover from react-bootstrap with Antd (#11163)

* New popover component

* LimitControl

* Moar components migrated

* TimeSeriesColumnControl

* Hotkeys

* ColorPicker

* FilterBoxItemCOntrol

* AdhocFilterEditPopover

* AdhocMetric

* AnnotationLayerControl

* DateFilterControl

* Tests fix

* Fix linting issue

* Fix tests

* Bug fix

* Test fix

* Remove Antd global stylesheet

* Fix linting

* Fix test

* Fix test

* Fix test

* Fix test

* Fix test
This commit is contained in:
Kamil Gabryjelski
2020-10-20 05:42:33 +02:00
committed by GitHub
parent 4208ca76e0
commit 901a42b1df
39 changed files with 942 additions and 874 deletions

View File

@@ -18,9 +18,8 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { Popover, Tab, Tabs } from 'react-bootstrap';
import { Tab, Tabs } from 'react-bootstrap';
import Button from 'src/components/Button';
import { ThemeProvider } from '@superset-ui/core';
import columnType from '../propTypes/columnType';
import adhocMetricType from '../propTypes/adhocMetricType';
@@ -132,80 +131,78 @@ export default class AdhocFilterEditPopover extends React.Component {
const hasUnsavedChanges = !adhocFilter.equals(propsAdhocFilter);
return (
<Popover
<div
id="filter-edit-popover"
{...popoverProps}
data-test="filter-edit-popover"
>
<ThemeProvider theme={theme}>
<Tabs
id="adhoc-filter-edit-tabs"
defaultActiveKey={adhocFilter.expressionType}
className="adhoc-filter-edit-tabs"
data-test="adhoc-filter-edit-tabs"
style={{ height: this.state.height, width: this.state.width }}
<Tabs
id="adhoc-filter-edit-tabs"
defaultActiveKey={adhocFilter.expressionType}
className="adhoc-filter-edit-tabs"
data-test="adhoc-filter-edit-tabs"
style={{ height: this.state.height, width: this.state.width }}
>
<Tab
className="adhoc-filter-edit-tab"
eventKey={EXPRESSION_TYPES.SIMPLE}
title="Simple"
>
<Tab
className="adhoc-filter-edit-tab"
eventKey={EXPRESSION_TYPES.SIMPLE}
title="Simple"
>
<AdhocFilterEditPopoverSimpleTabContent
<AdhocFilterEditPopoverSimpleTabContent
adhocFilter={this.state.adhocFilter}
onChange={this.onAdhocFilterChange}
options={options}
datasource={datasource}
onHeightChange={this.adjustHeight}
partitionColumn={partitionColumn}
/>
</Tab>
<Tab
className="adhoc-filter-edit-tab"
eventKey={EXPRESSION_TYPES.SQL}
title="Custom SQL"
>
{!this.props.datasource ||
this.props.datasource.type !== 'druid' ? (
<AdhocFilterEditPopoverSqlTabContent
adhocFilter={this.state.adhocFilter}
onChange={this.onAdhocFilterChange}
options={options}
datasource={datasource}
onHeightChange={this.adjustHeight}
partitionColumn={partitionColumn}
options={this.props.options}
height={this.state.height}
/>
</Tab>
<Tab
className="adhoc-filter-edit-tab"
eventKey={EXPRESSION_TYPES.SQL}
title="Custom SQL"
>
{!this.props.datasource ||
this.props.datasource.type !== 'druid' ? (
<AdhocFilterEditPopoverSqlTabContent
adhocFilter={this.state.adhocFilter}
onChange={this.onAdhocFilterChange}
options={this.props.options}
height={this.state.height}
/>
) : (
<div className="custom-sql-disabled-message">
Custom SQL Filters are not available on druid datasources
</div>
)}
</Tab>
</Tabs>
<div>
<Button
data-test="adhoc-filter-edit-popover-save-button"
disabled={!stateIsValid}
buttonStyle={
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
}
buttonSize="small"
className="m-r-5"
onClick={this.onSave}
cta
>
Save
</Button>
<Button buttonSize="small" onClick={this.props.onClose} cta>
Close
</Button>
<i
role="button"
aria-label="Resize"
tabIndex={0}
onMouseDown={this.onDragDown}
className="fa fa-expand edit-popover-resize text-muted"
/>
</div>
</ThemeProvider>
</Popover>
) : (
<div className="custom-sql-disabled-message">
Custom SQL Filters are not available on druid datasources
</div>
)}
</Tab>
</Tabs>
<div>
<Button
data-test="adhoc-filter-edit-popover-save-button"
disabled={!stateIsValid}
buttonStyle={
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
}
buttonSize="small"
className="m-r-5"
onClick={this.onSave}
cta
>
Save
</Button>
<Button buttonSize="small" onClick={this.props.onClose} cta>
Close
</Button>
<i
role="button"
aria-label="Resize"
tabIndex={0}
onMouseDown={this.onDragDown}
className="fa fa-expand edit-popover-resize text-muted"
/>
</div>
</div>
);
}
}

View File

@@ -18,7 +18,7 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger } from 'react-bootstrap';
import Popover from 'src/common/components/Popover';
import { t, withTheme } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
@@ -48,6 +48,7 @@ class AdhocFilterOption extends React.PureComponent {
this.onPopoverResize = this.onPopoverResize.bind(this);
this.onOverlayEntered = this.onOverlayEntered.bind(this);
this.onOverlayExited = this.onOverlayExited.bind(this);
this.handleVisibleChange = this.handleVisibleChange.bind(this);
this.state = { overlayShown: false };
}
@@ -68,12 +69,20 @@ class AdhocFilterOption extends React.PureComponent {
}
closeFilterEditOverlay() {
this.refs.overlay.hide();
this.setState({ overlayShown: false });
}
handleVisibleChange(visible) {
if (visible) {
this.onOverlayEntered();
} else {
this.onOverlayExited();
}
}
render() {
const { adhocFilter, theme } = this.props;
const overlay = (
const { adhocFilter } = this.props;
const content = (
<AdhocFilterEditPopover
onResize={this.onPopoverResize}
adhocFilter={adhocFilter}
@@ -82,11 +91,10 @@ class AdhocFilterOption extends React.PureComponent {
options={this.props.options}
datasource={this.props.datasource}
partitionColumn={this.props.partitionColumn}
theme={theme}
/>
);
return (
<div onMouseDownCapture={e => e.stopPropagation()}>
<div role="button" tabIndex={0} onMouseDown={e => e.stopPropagation()}>
{adhocFilter.isExtra && (
<InfoTooltipWithTrigger
icon="exclamation-triangle"
@@ -98,17 +106,14 @@ class AdhocFilterOption extends React.PureComponent {
`)}
/>
)}
<OverlayTrigger
ref="overlay"
<Popover
placement="right"
trigger="click"
disabled
overlay={overlay}
rootClose
shouldUpdatePosition
defaultOverlayShown={adhocFilter.isNew}
onEntered={this.onOverlayEntered}
onExited={this.onOverlayExited}
content={content}
defaultVisible={adhocFilter.isNew}
visible={this.state.overlayShown}
onVisibleChange={this.handleVisibleChange}
>
<Label className="option-label adhoc-option adhoc-filter-option">
{adhocFilter.getDefaultLabel()}
@@ -118,7 +123,7 @@ class AdhocFilterOption extends React.PureComponent {
} adhoc-label-arrow`}
/>
</Label>
</OverlayTrigger>
</Popover>
</div>
);
}

View File

@@ -18,10 +18,10 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { FormGroup, Popover, Tab, Tabs } from 'react-bootstrap';
import { FormGroup, Tab, Tabs } from 'react-bootstrap';
import Button from 'src/components/Button';
import Select from 'src/components/Select';
import { t, ThemeProvider } from '@superset-ui/core';
import { t } from '@superset-ui/core';
import { ColumnOption } from '@superset-ui/chart-controls';
import FormLabel from 'src/components/FormLabel';
@@ -29,7 +29,6 @@ import { SQLEditor } from 'src/components/AsyncAceEditor';
import sqlKeywords from 'src/SqlLab/utils/sqlKeywords';
import { AGGREGATES_OPTIONS } from '../constants';
import AdhocMetricEditPopoverTitle from './AdhocMetricEditPopoverTitle';
import columnType from '../propTypes/columnType';
import AdhocMetric, { EXPRESSION_TYPES } from '../AdhocMetric';
@@ -40,7 +39,10 @@ const propTypes = {
onResize: PropTypes.func.isRequired,
columns: PropTypes.arrayOf(columnType),
datasourceType: PropTypes.string,
theme: PropTypes.object,
title: PropTypes.shape({
label: PropTypes.string,
hasCustomLabel: PropTypes.bool,
}),
};
const defaultProps = {
@@ -57,7 +59,6 @@ export default class AdhocMetricEditPopover extends React.Component {
this.onColumnChange = this.onColumnChange.bind(this);
this.onAggregateChange = this.onAggregateChange.bind(this);
this.onSqlExpressionChange = this.onSqlExpressionChange.bind(this);
this.onLabelChange = this.onLabelChange.bind(this);
this.onDragDown = this.onDragDown.bind(this);
this.onMouseMove = this.onMouseMove.bind(this);
this.onMouseUp = this.onMouseUp.bind(this);
@@ -83,7 +84,10 @@ export default class AdhocMetricEditPopover extends React.Component {
}
onSave() {
this.props.onChange(this.state.adhocMetric);
this.props.onChange({
...this.state.adhocMetric,
...this.props.title,
});
this.props.onClose();
}
@@ -115,16 +119,6 @@ export default class AdhocMetricEditPopover extends React.Component {
}));
}
onLabelChange(e) {
const label = e.target.value;
this.setState(prevState => ({
adhocMetric: prevState.adhocMetric.duplicateWith({
label,
hasCustomLabel: true,
}),
}));
}
onDragDown(e) {
this.dragStartX = e.clientX;
this.dragStartY = e.clientY;
@@ -177,7 +171,6 @@ export default class AdhocMetricEditPopover extends React.Component {
onClose,
onResize,
datasourceType,
theme,
...popoverProps
} = this.props;
@@ -215,123 +208,113 @@ export default class AdhocMetricEditPopover extends React.Component {
);
}
const popoverTitle = (
<AdhocMetricEditPopoverTitle
adhocMetric={adhocMetric}
onChange={this.onLabelChange}
/>
);
const stateIsValid = adhocMetric.isValid();
const hasUnsavedChanges = !adhocMetric.equals(propsAdhocMetric);
return (
<Popover
<div
id="metrics-edit-popover"
data-test="metrics-edit-popover"
title={popoverTitle}
{...popoverProps}
>
<ThemeProvider theme={theme}>
<Tabs
id="adhoc-metric-edit-tabs"
data-test="adhoc-metric-edit-tabs"
defaultActiveKey={adhocMetric.expressionType}
className="adhoc-metric-edit-tabs"
style={{ height: this.state.height, width: this.state.width }}
onSelect={this.refreshAceEditor}
animation={false}
<Tabs
id="adhoc-metric-edit-tabs"
data-test="adhoc-metric-edit-tabs"
defaultActiveKey={adhocMetric.expressionType}
className="adhoc-metric-edit-tabs"
style={{ height: this.state.height, width: this.state.width }}
onSelect={this.refreshAceEditor}
animation={false}
>
<Tab
className="adhoc-metric-edit-tab"
eventKey={EXPRESSION_TYPES.SIMPLE}
title="Simple"
>
<Tab
className="adhoc-metric-edit-tab"
eventKey={EXPRESSION_TYPES.SIMPLE}
title="Simple"
>
<FormGroup>
<FormLabel>
<strong>column</strong>
</FormLabel>
<Select
name="select-column"
{...this.selectProps}
{...columnSelectProps}
<FormGroup>
<FormLabel>
<strong>column</strong>
</FormLabel>
<Select
name="select-column"
{...this.selectProps}
{...columnSelectProps}
/>
</FormGroup>
<FormGroup>
<FormLabel>
<strong>aggregate</strong>
</FormLabel>
<Select
name="select-aggregate"
{...this.selectProps}
{...aggregateSelectProps}
autoFocus
/>
</FormGroup>
</Tab>
<Tab
className="adhoc-metric-edit-tab"
eventKey={EXPRESSION_TYPES.SQL}
title="Custom SQL"
data-test="adhoc-metric-edit-tab#custom"
>
{this.props.datasourceType !== 'druid' ? (
<FormGroup data-test="sql-editor">
<SQLEditor
showLoadingForImport
ref={this.handleAceEditorRef}
keywords={keywords}
height={`${this.state.height - 43}px`}
onChange={this.onSqlExpressionChange}
width="100%"
showGutter={false}
value={
adhocMetric.sqlExpression || adhocMetric.translateToSql()
}
editorProps={{ $blockScrolling: true }}
enableLiveAutocompletion
className="adhoc-filter-sql-editor"
wrapEnabled
/>
</FormGroup>
<FormGroup>
<FormLabel>
<strong>aggregate</strong>
</FormLabel>
<Select
name="select-aggregate"
{...this.selectProps}
{...aggregateSelectProps}
autoFocus
/>
</FormGroup>
</Tab>
<Tab
className="adhoc-metric-edit-tab"
eventKey={EXPRESSION_TYPES.SQL}
title="Custom SQL"
data-test="adhoc-metric-edit-tab#custom"
>
{this.props.datasourceType !== 'druid' ? (
<FormGroup data-test="sql-editor">
<SQLEditor
showLoadingForImport
ref={this.handleAceEditorRef}
keywords={keywords}
height={`${this.state.height - 43}px`}
onChange={this.onSqlExpressionChange}
width="100%"
showGutter={false}
value={
adhocMetric.sqlExpression || adhocMetric.translateToSql()
}
editorProps={{ $blockScrolling: true }}
enableLiveAutocompletion
className="adhoc-filter-sql-editor"
wrapEnabled
/>
</FormGroup>
) : (
<div className="custom-sql-disabled-message">
Custom SQL Metrics are not available on druid datasources
</div>
)}
</Tab>
</Tabs>
<div>
<Button
disabled={!stateIsValid}
buttonStyle={
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
}
buttonSize="small"
className="m-r-5"
data-test="AdhocMetricEdit#save"
onClick={this.onSave}
cta
>
Save
</Button>
<Button
buttonSize="small"
onClick={this.props.onClose}
data-test="AdhocMetricEdit#cancel"
cta
>
Close
</Button>
<i
role="button"
aria-label="Resize"
tabIndex={0}
onMouseDown={this.onDragDown}
className="fa fa-expand edit-popover-resize text-muted"
/>
</div>
</ThemeProvider>
</Popover>
) : (
<div className="custom-sql-disabled-message">
Custom SQL Metrics are not available on druid datasources
</div>
)}
</Tab>
</Tabs>
<div>
<Button
disabled={!stateIsValid}
buttonStyle={
hasUnsavedChanges && stateIsValid ? 'primary' : 'default'
}
buttonSize="small"
className="m-r-5"
data-test="AdhocMetricEdit#save"
onClick={this.onSave}
cta
>
Save
</Button>
<Button
buttonSize="small"
onClick={this.props.onClose}
data-test="AdhocMetricEdit#cancel"
cta
>
Close
</Button>
<i
role="button"
aria-label="Resize"
tabIndex={0}
onMouseDown={this.onDragDown}
className="fa fa-expand edit-popover-resize text-muted"
/>
</div>
</div>
);
}
}

View File

@@ -19,10 +19,13 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormControl, OverlayTrigger, Tooltip } from 'react-bootstrap';
import AdhocMetric from '../AdhocMetric';
const propTypes = {
adhocMetric: PropTypes.instanceOf(AdhocMetric),
title: PropTypes.shape({
label: PropTypes.string,
hasCustomLabel: PropTypes.bool,
}),
defaultLabel: PropTypes.string,
onChange: PropTypes.func.isRequired,
};
@@ -33,6 +36,7 @@ export default class AdhocMetricEditPopoverTitle extends React.Component {
this.onMouseOut = this.onMouseOut.bind(this);
this.onClick = this.onClick.bind(this);
this.onBlur = this.onBlur.bind(this);
this.onInputBlur = this.onInputBlur.bind(this);
this.state = {
isHovered: false,
isEditable: false,
@@ -55,8 +59,16 @@ export default class AdhocMetricEditPopoverTitle extends React.Component {
this.setState({ isEditable: false });
}
onInputBlur(e) {
if (e.target.value === '') {
e.target.value = this.props.defaultLabel;
this.props.onChange(e);
}
this.onBlur();
}
render() {
const { adhocMetric, onChange } = this.props;
const { title, onChange } = this.props;
const editPrompt = (
<Tooltip id="edit-metric-label-tooltip">Click to edit label</Tooltip>
@@ -66,10 +78,11 @@ export default class AdhocMetricEditPopoverTitle extends React.Component {
<FormControl
className="metric-edit-popover-label-input"
type="text"
placeholder={adhocMetric.label}
value={adhocMetric.hasCustomLabel ? adhocMetric.label : ''}
placeholder={title.label}
value={title.hasCustomLabel ? title.label : ''}
autoFocus
onChange={onChange}
onBlur={this.onInputBlur}
data-test="AdhocMetricEditTitle#input"
/>
) : (
@@ -86,7 +99,7 @@ export default class AdhocMetricEditPopoverTitle extends React.Component {
className="inline-editable"
data-test="AdhocMetricEditTitle#trigger"
>
{adhocMetric.hasCustomLabel ? adhocMetric.label : 'My Metric'}
{title.hasCustomLabel ? title.label : 'My Metric'}
&nbsp;
<i
className="fa fa-pencil"

View File

@@ -18,10 +18,11 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger } from 'react-bootstrap';
import { withTheme } from '@superset-ui/core';
import Popover from 'src/common/components/Popover';
import Label from 'src/components/Label';
import AdhocMetricEditPopoverTitle from 'src/explore/components/AdhocMetricEditPopoverTitle';
import AdhocMetricEditPopover from './AdhocMetricEditPopover';
import AdhocMetric from '../AdhocMetric';
import columnType from '../propTypes/columnType';
@@ -39,10 +40,26 @@ class AdhocMetricOption extends React.PureComponent {
super(props);
this.closeMetricEditOverlay = this.closeMetricEditOverlay.bind(this);
this.onOverlayEntered = this.onOverlayEntered.bind(this);
this.onOverlayExited = this.onOverlayExited.bind(this);
this.onPopoverResize = this.onPopoverResize.bind(this);
this.state = { overlayShown: false };
this.overlay = null;
this.handleVisibleChange = this.handleVisibleChange.bind(this);
this.onLabelChange = this.onLabelChange.bind(this);
this.state = {
overlayShown: false,
title: {
label: props.adhocMetric.label,
hasCustomLabel: props.adhocMetric.hasCustomLabel,
},
};
}
onLabelChange(e) {
const label = e.target.value;
this.setState({
title: {
label,
hasCustomLabel: true,
},
});
}
onPopoverResize() {
@@ -54,28 +71,46 @@ class AdhocMetricOption extends React.PureComponent {
// once the overlay has been opened, the metric/filter will never be
// considered new again.
this.props.adhocMetric.isNew = false;
this.setState({ overlayShown: true });
}
onOverlayExited() {
this.setState({ overlayShown: false });
this.setState({
overlayShown: true,
title: {
label: this.props.adhocMetric.label,
hasCustomLabel: this.props.adhocMetric.hasCustomLabel,
},
});
}
closeMetricEditOverlay() {
this.overlay.hide();
this.setState({ overlayShown: false });
}
handleVisibleChange(visible) {
if (visible) {
this.onOverlayEntered();
} else {
this.closeMetricEditOverlay();
}
}
render() {
const { adhocMetric, theme } = this.props;
const { adhocMetric } = this.props;
const overlayContent = (
<AdhocMetricEditPopover
onResize={this.onPopoverResize}
adhocMetric={adhocMetric}
title={this.state.title}
onChange={this.props.onMetricEdit}
onClose={this.closeMetricEditOverlay}
columns={this.props.columns}
datasourceType={this.props.datasourceType}
theme={theme}
/>
);
const popoverTitle = (
<AdhocMetricEditPopoverTitle
title={this.state.title}
defaultLabel={adhocMetric.label}
onChange={this.onLabelChange}
/>
);
@@ -83,23 +118,22 @@ class AdhocMetricOption extends React.PureComponent {
<div
className="metric-option"
data-test="metric-option"
onMouseDownCapture={e => e.stopPropagation()}
role="button"
tabIndex={0}
onMouseDown={e => e.stopPropagation()}
onKeyDown={e => e.stopPropagation()}
>
<OverlayTrigger
ref={ref => {
this.overlay = ref;
}}
<Popover
placement="right"
trigger="click"
disabled
overlay={overlayContent}
rootClose
shouldUpdatePosition
defaultOverlayShown={adhocMetric.isNew}
onEntered={this.onOverlayEntered}
onExited={this.onOverlayExited}
content={overlayContent}
defaultVisible={adhocMetric.isNew}
onVisibleChange={this.handleVisibleChange}
visible={this.state.overlayShown}
title={popoverTitle}
>
<Label className="option-label adhoc-option">
<Label className="option-label adhoc-option" data-test="option-label">
{adhocMetric.label}
<i
className={`fa fa-caret-${
@@ -107,7 +141,7 @@ class AdhocMetricOption extends React.PureComponent {
} adhoc-label-arrow`}
/>
</Label>
</OverlayTrigger>
</Popover>
</div>
);
}

View File

@@ -18,13 +18,13 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { Popover, OverlayTrigger } from 'react-bootstrap';
import { t } from '@superset-ui/core';
import Popover from 'src/common/components/Popover';
import FormLabel from 'src/components/FormLabel';
import CopyToClipboard from 'src/components/CopyToClipboard';
import { getShortUrl } from 'src/utils/common';
import { getExploreLongUrl, getURIDirectory } from '../exploreUtils';
import { getShortUrl } from '../../utils/common';
const propTypes = {
latestQueryFormData: PropTypes.object.isRequired,
@@ -80,86 +80,80 @@ export default class EmbedCodeButton extends React.Component {
);
}
renderPopover() {
renderPopoverContent() {
const html = this.generateEmbedHTML();
return (
<Popover id="embed-code-popover" data-test="embed-code-popover">
<div>
<div className="row">
<div className="col-sm-10">
<textarea
data-test="embed-code-textarea"
name="embedCode"
value={html}
rows="4"
readOnly
<div id="embed-code-popover" data-test="embed-code-popover">
<div className="row">
<div className="col-sm-10">
<textarea
data-test="embed-code-textarea"
name="embedCode"
value={html}
rows="4"
readOnly
className="form-control input-sm"
/>
</div>
<div className="col-sm-2">
<CopyToClipboard
shouldShowText={false}
text={html}
copyNode={
<i className="fa fa-clipboard" title={t('Copy to clipboard')} />
}
/>
</div>
</div>
<br />
<div className="row">
<div className="col-md-6 col-sm-12">
<div className="form-group">
<small>
<FormLabel htmlFor="embed-height">{t('Height')}</FormLabel>
</small>
<input
className="form-control input-sm"
/>
</div>
<div className="col-sm-2">
<CopyToClipboard
shouldShowText={false}
text={html}
copyNode={
<i
className="fa fa-clipboard"
title={t('Copy to clipboard')}
/>
}
type="text"
defaultValue={this.state.height}
name="height"
onChange={this.handleInputChange}
/>
</div>
</div>
<br />
<div className="row">
<div className="col-md-6 col-sm-12">
<div className="form-group">
<small>
<FormLabel htmlFor="embed-height">{t('Height')}</FormLabel>
</small>
<input
className="form-control input-sm"
type="text"
defaultValue={this.state.height}
name="height"
onChange={this.handleInputChange}
/>
</div>
</div>
<div className="col-md-6 col-sm-12">
<div className="form-group">
<small>
<FormLabel htmlFor="embed-width">{t('Width')}</FormLabel>
</small>
<input
className="form-control input-sm"
type="text"
defaultValue={this.state.width}
name="width"
onChange={this.handleInputChange}
id="embed-width"
/>
</div>
<div className="col-md-6 col-sm-12">
<div className="form-group">
<small>
<FormLabel htmlFor="embed-width">{t('Width')}</FormLabel>
</small>
<input
className="form-control input-sm"
type="text"
defaultValue={this.state.width}
name="width"
onChange={this.handleInputChange}
id="embed-width"
/>
</div>
</div>
</div>
</Popover>
</div>
);
}
render() {
return (
<OverlayTrigger
<Popover
trigger="click"
rootClose
placement="left"
onEnter={this.getCopyUrl}
overlay={this.renderPopover()}
onClick={this.getCopyUrl}
content={this.renderPopoverContent()}
>
<span className="btn btn-default btn-sm" data-test="embed-code-button">
<i className="fa fa-code" />
&nbsp;
</span>
</OverlayTrigger>
</Popover>
);
}
}

View File

@@ -26,7 +26,6 @@ import {
SupersetClient,
getCategoricalSchemeRegistry,
getChartMetadataRegistry,
ThemeProvider,
validateNonEmpty,
} from '@superset-ui/core';
@@ -67,7 +66,6 @@ const propTypes = {
timeColumn: PropTypes.string,
intervalEndColumn: PropTypes.string,
vizType: PropTypes.string,
theme: PropTypes.object,
error: PropTypes.string,
colorScheme: PropTypes.string,
@@ -666,7 +664,6 @@ export default class AnnotationLayer extends React.PureComponent {
render() {
const { isNew, name, annotationType, sourceType, show } = this.state;
const isValid = this.isValidForm();
const { theme } = this.props;
const metadata = getChartMetadataRegistry().get(this.props.vizType);
const supportedAnnotationTypes = metadata
? metadata.supportedAnnotationTypes.map(
@@ -676,7 +673,7 @@ export default class AnnotationLayer extends React.PureComponent {
const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
return (
<ThemeProvider theme={theme}>
<>
{this.props.error && (
<span style={{ color: 'red' }}>ERROR: {this.props.error}</span>
)}
@@ -750,7 +747,7 @@ export default class AnnotationLayer extends React.PureComponent {
</Button>
</div>
</div>
</ThemeProvider>
</>
);
}
}

View File

@@ -18,15 +18,11 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
OverlayTrigger,
Popover,
ListGroup,
ListGroupItem,
} from 'react-bootstrap';
import { ListGroup, ListGroupItem } from 'react-bootstrap';
import { connect } from 'react-redux';
import { t, withTheme } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import Popover from 'src/common/components/Popover';
import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
import { getChartKey } from 'src/explore/exploreUtils';
import { runAnnotationQuery } from 'src/chart/chartAction';
@@ -62,8 +58,10 @@ const defaultProps = {
class AnnotationLayerControl extends React.PureComponent {
constructor(props) {
super(props);
this.state = { popoverVisible: false };
this.addAnnotationLayer = this.addAnnotationLayer.bind(this);
this.removeAnnotationLayer = this.removeAnnotationLayer.bind(this);
this.handleVisibleChange = this.handleVisibleChange.bind(this);
}
componentDidMount() {
@@ -101,6 +99,12 @@ class AnnotationLayerControl extends React.PureComponent {
this.props.onChange(annotations);
}
handleVisibleChange(visible, popoverKey) {
this.setState(prevState => ({
popoverVisible: { ...prevState, [popoverKey]: visible },
}));
}
removeAnnotationLayer(annotation) {
const annotations = this.props.value
.slice()
@@ -108,18 +112,10 @@ class AnnotationLayerControl extends React.PureComponent {
this.props.onChange(annotations);
}
renderPopover(parent, annotation, error) {
renderPopover(parent, popoverKey, annotation, error) {
const id = !annotation ? '_new' : annotation.name;
const { theme } = this.props;
return (
<Popover
data-test="annotation-popover"
style={{ maxWidth: 'none' }}
title={
annotation ? t('Edit Annotation Layer') : t('Add Annotation Layer')
}
id={`annotation-pop-${id}`}
>
<div id={`annotation-pop-${id}`} data-test="popover-content">
<AnnotationLayer
{...annotation}
parent={this.refs[parent]}
@@ -128,10 +124,9 @@ class AnnotationLayerControl extends React.PureComponent {
vizType={this.props.vizType}
addAnnotationLayer={this.addAnnotationLayer}
removeAnnotationLayer={this.removeAnnotationLayer}
close={() => this.refs[parent].hide()}
theme={theme}
close={() => this.handleVisibleChange(false, popoverKey)}
/>
</Popover>
</div>
);
}
@@ -159,34 +154,41 @@ class AnnotationLayerControl extends React.PureComponent {
render() {
const annotations = this.props.value.map((anno, i) => (
<OverlayTrigger
<Popover
key={i}
trigger="click"
rootClose
ref={`overlay-${i}`}
placement="right"
overlay={this.renderPopover(
title={t('Edit Annotation Layer')}
content={this.renderPopover(
`overlay-${i}`,
i,
anno,
this.props.annotationError[anno.name],
)}
visible={this.state.popoverVisible[i]}
onVisibleChange={visible => this.handleVisibleChange(visible, i)}
>
<ListGroupItem>
<span>{anno.name}</span>
<span style={{ float: 'right' }}>{this.renderInfo(anno)}</span>
</ListGroupItem>
</OverlayTrigger>
</Popover>
));
const addLayerPopoverKey = 'add';
return (
<div>
<ListGroup>
{annotations}
<OverlayTrigger
<Popover
trigger="click"
rootClose
ref="overlay-new"
placement="right"
overlay={this.renderPopover('overlay-new')}
content={this.renderPopover('overlay-new', addLayerPopoverKey)}
title={t('Add Annotation Layer')}
visible={this.state.popoverVisible[addLayerPopoverKey]}
onVisibleChange={visible =>
this.handleVisibleChange(visible, addLayerPopoverKey)
}
>
<ListGroupItem>
<i
@@ -195,7 +197,7 @@ class AnnotationLayerControl extends React.PureComponent {
/>{' '}
&nbsp; {t('Add Annotation Layer')}
</ListGroupItem>
</OverlayTrigger>
</Popover>
</ListGroup>
</div>
);

View File

@@ -18,9 +18,9 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { SketchPicker } from 'react-color';
import { getCategoricalSchemeRegistry } from '@superset-ui/core';
import Popover from 'src/common/components/Popover';
import ControlHeader from '../ControlHeader';
const propTypes = {
@@ -79,13 +79,13 @@ export default class ColorPickerControl extends React.Component {
.get()
.colors.filter((s, i) => i < 7);
return (
<Popover id="filter-popover" className="color-popover">
<div id="filter-popover" className="color-popover">
<SketchPicker
color={this.props.value}
onChange={this.onChange}
presetColors={presetColors}
/>
</Popover>
</div>
);
}
@@ -98,19 +98,16 @@ export default class ColorPickerControl extends React.Component {
return (
<div>
<ControlHeader {...this.props} />
<OverlayTrigger
container={document.body}
<Popover
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
content={this.renderPopover()}
>
<div style={styles.swatch}>
<div style={styles.checkboard} />
<div style={colStyle} />
</div>
</OverlayTrigger>
</Popover>
</div>
);
}

View File

@@ -25,12 +25,12 @@ import {
InputGroup,
MenuItem,
OverlayTrigger,
Popover,
Radio,
Tab,
Tabs,
Tooltip,
} from 'react-bootstrap';
import Popover from 'src/common/components/Popover';
import Button from 'src/components/Button';
import Datetime from 'react-datetime';
import 'react-datetime/css/react-datetime.css';
@@ -206,6 +206,8 @@ class DateFilterControl extends React.Component {
showUntilCalendar: false,
sinceViewMode: 'days',
untilViewMode: 'days',
popoverVisible: false,
};
const { value } = props;
@@ -230,6 +232,7 @@ class DateFilterControl extends React.Component {
this.setTypeCustomStartEnd = this.setTypeCustomStartEnd.bind(this);
this.toggleCalendar = this.toggleCalendar.bind(this);
this.changeTab = this.changeTab.bind(this);
this.handleVisibleChange = this.handleVisibleChange.bind(this);
}
componentDidMount() {
@@ -328,8 +331,11 @@ class DateFilterControl extends React.Component {
}
this.props.onCloseDateFilterControl();
this.props.onChange(val);
this.refs.trigger.hide();
this.setState({ showSinceCalendar: false, showUntilCalendar: false });
this.setState({
showSinceCalendar: false,
showUntilCalendar: false,
popoverVisible: false,
});
}
isValidSince(date) {
@@ -362,6 +368,10 @@ class DateFilterControl extends React.Component {
this.setState(nextState);
}
handleVisibleChange(visible) {
this.setState({ popoverVisible: visible });
}
renderInput(props, key) {
return (
<FormGroup>
@@ -374,7 +384,7 @@ class DateFilterControl extends React.Component {
onClick={() => {}}
/>
<InputGroup.Button onClick={() => this.toggleCalendar(key)}>
<Button theme={this.props.theme}>
<Button>
<i className="fa fa-calendar" />
</Button>
</InputGroup.Button>
@@ -400,7 +410,7 @@ class DateFilterControl extends React.Component {
const timeRange = buildTimeRangeString(nextState.since, nextState.until);
return (
<Styles theme={this.props.theme} key={timeFrame}>
<Styles key={timeFrame}>
<OverlayTrigger
key={timeFrame}
placement="right"
@@ -424,168 +434,166 @@ class DateFilterControl extends React.Component {
);
});
return (
<Popover id="filter-popover" placement="top" positionTop={0}>
<div
style={DATE_FILTER_POPOVER_STYLE}
ref={ref => {
this.popoverContainer = ref;
}}
<div
id="filter-popover"
style={DATE_FILTER_POPOVER_STYLE}
ref={ref => {
this.popoverContainer = ref;
}}
>
<Tabs
defaultActiveKey={this.state.tab === TABS.DEFAULTS ? 1 : 2}
id="type"
className="time-filter-tabs"
onSelect={this.changeTab}
>
<Tabs
defaultActiveKey={this.state.tab === TABS.DEFAULTS ? 1 : 2}
id="type"
className="time-filter-tabs"
onSelect={this.changeTab}
>
<Tab eventKey={1} title="Defaults">
<FormGroup>{timeFrames}</FormGroup>
</Tab>
<Tab eventKey={2} title="Custom">
<FormGroup>
<PopoverSection
title="Relative to today"
isSelected={this.state.type === TYPES.CUSTOM_RANGE}
onSelect={this.setTypeCustomRange}
<Tab eventKey={1} title="Defaults">
<FormGroup>{timeFrames}</FormGroup>
</Tab>
<Tab eventKey={2} title="Custom">
<FormGroup>
<PopoverSection
title="Relative to today"
isSelected={this.state.type === TYPES.CUSTOM_RANGE}
onSelect={this.setTypeCustomRange}
>
<div
className="clearfix centered"
style={{ marginTop: '12px' }}
>
<div
className="clearfix centered"
style={{ marginTop: '12px' }}
style={{ width: '60px', marginTop: '-4px' }}
className="input-inline"
>
<div
style={{ width: '60px', marginTop: '-4px' }}
className="input-inline"
<DropdownButton
bsSize="small"
componentClass={InputGroup.Button}
id="input-dropdown-rel"
title={this.state.rel}
onFocus={this.setTypeCustomRange}
>
<DropdownButton
bsSize="small"
componentClass={InputGroup.Button}
id="input-dropdown-rel"
title={this.state.rel}
onFocus={this.setTypeCustomRange}
<MenuItem
onSelect={value => this.setCustomRange('rel', value)}
key={RELATIVE_TIME_OPTIONS.LAST}
eventKey={RELATIVE_TIME_OPTIONS.LAST}
active={this.state.rel === RELATIVE_TIME_OPTIONS.LAST}
>
<MenuItem
onSelect={value => this.setCustomRange('rel', value)}
key={RELATIVE_TIME_OPTIONS.LAST}
eventKey={RELATIVE_TIME_OPTIONS.LAST}
active={this.state.rel === RELATIVE_TIME_OPTIONS.LAST}
>
Last
</MenuItem>
<MenuItem
onSelect={value => this.setCustomRange('rel', value)}
key={RELATIVE_TIME_OPTIONS.NEXT}
eventKey={RELATIVE_TIME_OPTIONS.NEXT}
active={this.state.rel === RELATIVE_TIME_OPTIONS.NEXT}
>
Next
</MenuItem>
</DropdownButton>
</div>
<div
style={{ width: '60px', marginTop: '-4px' }}
className="input-inline m-l-5 m-r-3"
Last
</MenuItem>
<MenuItem
onSelect={value => this.setCustomRange('rel', value)}
key={RELATIVE_TIME_OPTIONS.NEXT}
eventKey={RELATIVE_TIME_OPTIONS.NEXT}
active={this.state.rel === RELATIVE_TIME_OPTIONS.NEXT}
>
Next
</MenuItem>
</DropdownButton>
</div>
<div
style={{ width: '60px', marginTop: '-4px' }}
className="input-inline m-l-5 m-r-3"
>
<FormControl
bsSize="small"
type="text"
onChange={event =>
this.setCustomRange('num', event.target.value)
}
onFocus={this.setTypeCustomRange}
onKeyPress={this.onEnter}
value={this.state.num}
style={{ height: '30px' }}
/>
</div>
<div
style={{ width: '90px', marginTop: '-4px' }}
className="input-inline"
>
<DropdownButton
bsSize="small"
componentClass={InputGroup.Button}
id="input-dropdown-grain"
title={this.state.grain}
onFocus={this.setTypeCustomRange}
>
<FormControl
bsSize="small"
type="text"
onChange={event =>
this.setCustomRange('num', event.target.value)
{grainOptions}
</DropdownButton>
</div>
</div>
</PopoverSection>
<PopoverSection
title="Start / end"
isSelected={this.state.type === TYPES.CUSTOM_START_END}
onSelect={this.setTypeCustomStartEnd}
info={FREEFORM_TOOLTIP}
>
<div
ref={ref => {
this.startEndSectionRef = ref;
}}
>
<InputGroup data-test="date-input-group">
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-from-input' }}
value={this.state.since}
defaultValue={this.state.since}
viewDate={this.state.since}
onChange={value =>
this.setCustomStartEnd('since', value)
}
isValidDate={this.isValidSince}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showSinceCalendar')
}
open={this.state.showSinceCalendar}
viewMode={this.state.sinceViewMode}
onViewModeChange={sinceViewMode =>
this.setState({ sinceViewMode })
}
onFocus={this.setTypeCustomRange}
onKeyPress={this.onEnter}
value={this.state.num}
style={{ height: '30px' }}
/>
</div>
<div
style={{ width: '90px', marginTop: '-4px' }}
className="input-inline"
>
<DropdownButton
bsSize="small"
componentClass={InputGroup.Button}
id="input-dropdown-grain"
title={this.state.grain}
onFocus={this.setTypeCustomRange}
>
{grainOptions}
</DropdownButton>
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-to-input' }}
value={this.state.until}
defaultValue={this.state.until}
viewDate={this.state.until}
onChange={value =>
this.setCustomStartEnd('until', value)
}
isValidDate={this.isValidUntil}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showUntilCalendar')
}
open={this.state.showUntilCalendar}
viewMode={this.state.untilViewMode}
onViewModeChange={untilViewMode =>
this.setState({ untilViewMode })
}
/>
</div>
</div>
</PopoverSection>
<PopoverSection
title="Start / end"
isSelected={this.state.type === TYPES.CUSTOM_START_END}
onSelect={this.setTypeCustomStartEnd}
info={FREEFORM_TOOLTIP}
>
<div
ref={ref => {
this.startEndSectionRef = ref;
}}
>
<InputGroup data-test="date-input-group">
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-from-input' }}
value={this.state.since}
defaultValue={this.state.since}
viewDate={this.state.since}
onChange={value =>
this.setCustomStartEnd('since', value)
}
isValidDate={this.isValidSince}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showSinceCalendar')
}
open={this.state.showSinceCalendar}
viewMode={this.state.sinceViewMode}
onViewModeChange={sinceViewMode =>
this.setState({ sinceViewMode })
}
/>
</div>
<div style={{ margin: '5px 0' }}>
<Datetime
inputProps={{ 'data-test': 'date-to-input' }}
value={this.state.until}
defaultValue={this.state.until}
viewDate={this.state.until}
onChange={value =>
this.setCustomStartEnd('until', value)
}
isValidDate={this.isValidUntil}
onClick={this.setTypeCustomStartEnd}
renderInput={props =>
this.renderInput(props, 'showUntilCalendar')
}
open={this.state.showUntilCalendar}
viewMode={this.state.untilViewMode}
onViewModeChange={untilViewMode =>
this.setState({ untilViewMode })
}
/>
</div>
</InputGroup>
</div>
</PopoverSection>
</FormGroup>
</Tab>
</Tabs>
<div className="clearfix">
<Button
data-test="date-ok-button"
buttonSize="small"
className="float-right ok"
buttonStyle="primary"
onClick={this.close}
theme={this.props.theme}
>
Ok
</Button>
</div>
</InputGroup>
</div>
</PopoverSection>
</FormGroup>
</Tab>
</Tabs>
<div className="clearfix">
<Button
data-test="date-ok-button"
buttonSize="small"
className="float-right ok"
buttonStyle="primary"
onClick={this.close}
>
Ok
</Button>
</div>
</Popover>
</div>
);
}
@@ -594,15 +602,13 @@ class DateFilterControl extends React.Component {
return (
<div>
<ControlHeader {...this.props} />
<OverlayTrigger
animation={this.props.animation}
container={document.body}
<Popover
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
content={this.renderPopover()}
onClick={this.handleClickTrigger}
visible={this.state.popoverVisible}
onVisibleChange={this.handleVisibleChange}
>
<Label
name="popover-trigger"
@@ -611,7 +617,7 @@ class DateFilterControl extends React.Component {
>
{formatTimeRange(timeRange, this.props.endpoints)}
</Label>
</OverlayTrigger>
</Popover>
</div>
);
}

View File

@@ -18,10 +18,10 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { OverlayTrigger, Popover } from 'react-bootstrap';
import { t } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
import Popover from 'src/common/components/Popover';
import FormRow from '../../../components/FormRow';
import SelectControl from './SelectControl';
import CheckboxControl from './CheckboxControl';
@@ -81,7 +81,7 @@ export default class FilterBoxItemControl extends React.Component {
label,
defaultValue,
} = props;
const state = {
this.state = {
column,
metric,
label,
@@ -91,7 +91,6 @@ export default class FilterBoxItemControl extends React.Component {
searchAllOptions,
defaultValue,
};
this.state = state;
this.onChange = this.onChange.bind(this);
this.onControlChange = this.onControlChange.bind(this);
}
@@ -265,9 +264,9 @@ export default class FilterBoxItemControl extends React.Component {
renderPopover() {
return (
<Popover id="ts-col-popo" title={t('Filter Configuration')}>
<div style={STYLE_WIDTH}>{this.renderForm()}</div>
</Popover>
<div id="ts-col-popo" style={STYLE_WIDTH}>
{this.renderForm()}
</div>
);
}
@@ -275,20 +274,18 @@ export default class FilterBoxItemControl extends React.Component {
return (
<span>
{this.textSummary()}{' '}
<OverlayTrigger
container={document.body}
<Popover
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
content={this.renderPopover()}
title={t('Filter Configuration')}
>
<InfoTooltipWithTrigger
icon="edit"
className="text-primary"
label="edit-ts-column"
/>
</OverlayTrigger>
</Popover>
</span>
);
}

View File

@@ -18,13 +18,8 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
Row,
Col,
FormControl,
OverlayTrigger,
Popover,
} from 'react-bootstrap';
import { Row, Col, FormControl } from 'react-bootstrap';
import Popover from 'src/common/components/Popover';
import Select from 'src/components/Select';
import { t } from '@superset-ui/core';
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
@@ -153,159 +148,157 @@ export default class TimeSeriesColumnControl extends React.Component {
renderPopover() {
return (
<Popover id="ts-col-popo" title="Column Configuration">
<div style={{ width: 300 }}>
{this.formRow(
'Label',
'The column header label',
<div id="ts-col-popo" style={{ width: 300 }}>
{this.formRow(
'Label',
'The column header label',
'time-lag',
<FormControl
value={this.state.label}
onChange={this.onTextInputChange.bind(this, 'label')}
bsSize="small"
placeholder="Label"
/>,
)}
{this.formRow(
'Tooltip',
'Column header tooltip',
'col-tooltip',
<FormControl
value={this.state.tooltip}
onChange={this.onTextInputChange.bind(this, 'tooltip')}
bsSize="small"
placeholder="Tooltip"
/>,
)}
{this.formRow(
'Type',
'Type of comparison, value difference or percentage',
'col-type',
<Select
value={this.state.colType}
clearable={false}
onChange={this.onSelectChange.bind(this, 'colType')}
options={colTypeOptions}
/>,
)}
<hr />
{this.state.colType === 'spark' &&
this.formRow(
'Width',
'Width of the sparkline',
'spark-width',
<FormControl
value={this.state.width}
onChange={this.onTextInputChange.bind(this, 'width')}
bsSize="small"
placeholder="Width"
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Height',
'Height of the sparkline',
'spark-width',
<FormControl
value={this.state.height}
onChange={this.onTextInputChange.bind(this, 'height')}
bsSize="small"
placeholder="height"
/>,
)}
{['time', 'avg'].indexOf(this.state.colType) >= 0 &&
this.formRow(
'Time Lag',
'Number of periods to compare against',
'time-lag',
<FormControl
value={this.state.label}
onChange={this.onTextInputChange.bind(this, 'label')}
value={this.state.timeLag}
onChange={this.onTextInputChange.bind(this, 'timeLag')}
bsSize="small"
placeholder="Label"
placeholder="Time Lag"
/>,
)}
{this.formRow(
'Tooltip',
'Column header tooltip',
'col-tooltip',
{['spark'].indexOf(this.state.colType) >= 0 &&
this.formRow(
'Time Ratio',
'Number of periods to ratio against',
'time-ratio',
<FormControl
value={this.state.tooltip}
onChange={this.onTextInputChange.bind(this, 'tooltip')}
value={this.state.timeRatio}
onChange={this.onTextInputChange.bind(this, 'timeRatio')}
bsSize="small"
placeholder="Tooltip"
placeholder="Time Ratio"
/>,
)}
{this.formRow(
{this.state.colType === 'time' &&
this.formRow(
'Type',
'Type of comparison, value difference or percentage',
'col-type',
'comp-type',
<Select
value={this.state.colType}
value={this.state.comparisonType}
clearable={false}
onChange={this.onSelectChange.bind(this, 'colType')}
options={colTypeOptions}
onChange={this.onSelectChange.bind(this, 'comparisonType')}
options={comparisonTypeOptions}
/>,
)}
<hr />
{this.state.colType === 'spark' &&
this.formRow(
'Width',
'Width of the sparkline',
'spark-width',
<FormControl
value={this.state.width}
onChange={this.onTextInputChange.bind(this, 'width')}
bsSize="small"
placeholder="Width"
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Height',
'Height of the sparkline',
'spark-width',
<FormControl
value={this.state.height}
onChange={this.onTextInputChange.bind(this, 'height')}
bsSize="small"
placeholder="height"
/>,
)}
{['time', 'avg'].indexOf(this.state.colType) >= 0 &&
this.formRow(
'Time Lag',
'Number of periods to compare against',
'time-lag',
<FormControl
value={this.state.timeLag}
onChange={this.onTextInputChange.bind(this, 'timeLag')}
bsSize="small"
placeholder="Time Lag"
/>,
)}
{['spark'].indexOf(this.state.colType) >= 0 &&
this.formRow(
'Time Ratio',
'Number of periods to ratio against',
'time-ratio',
<FormControl
value={this.state.timeRatio}
onChange={this.onTextInputChange.bind(this, 'timeRatio')}
bsSize="small"
placeholder="Time Ratio"
/>,
)}
{this.state.colType === 'time' &&
this.formRow(
'Type',
'Type of comparison, value difference or percentage',
'comp-type',
<Select
value={this.state.comparisonType}
clearable={false}
onChange={this.onSelectChange.bind(this, 'comparisonType')}
options={comparisonTypeOptions}
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Show Y-axis',
'Show Y-axis on the sparkline. Will display the manually set min/max if set or min/max values in the data otherwise.',
'show-y-axis-bounds',
<CheckboxControl
value={this.state.showYAxis}
onChange={this.onCheckboxChange.bind(this, 'showYAxis')}
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Y-axis bounds',
'Manually set min/max values for the y-axis.',
'y-axis-bounds',
<BoundsControl
value={this.state.yAxisBounds}
onChange={this.onYAxisBoundsChange.bind(this)}
/>,
)}
{this.state.colType !== 'spark' &&
this.formRow(
'Color bounds',
`Number bounds used for color encoding from red to blue.
{this.state.colType === 'spark' &&
this.formRow(
'Show Y-axis',
'Show Y-axis on the sparkline. Will display the manually set min/max if set or min/max values in the data otherwise.',
'show-y-axis-bounds',
<CheckboxControl
value={this.state.showYAxis}
onChange={this.onCheckboxChange.bind(this, 'showYAxis')}
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Y-axis bounds',
'Manually set min/max values for the y-axis.',
'y-axis-bounds',
<BoundsControl
value={this.state.yAxisBounds}
onChange={this.onYAxisBoundsChange.bind(this)}
/>,
)}
{this.state.colType !== 'spark' &&
this.formRow(
'Color bounds',
`Number bounds used for color encoding from red to blue.
Reverse the numbers for blue to red. To get pure red or blue,
you can enter either only min or max.`,
'bounds',
<BoundsControl
value={this.state.bounds}
onChange={this.onBoundsChange.bind(this)}
/>,
)}
{this.formRow(
'Number format',
'Optional d3 number format string',
'd3-format',
<FormControl
value={this.state.d3format}
onChange={this.onTextInputChange.bind(this, 'd3format')}
bsSize="small"
placeholder="Number format string"
'bounds',
<BoundsControl
value={this.state.bounds}
onChange={this.onBoundsChange.bind(this)}
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Date format',
'Optional d3 date format string',
'date-format',
<FormControl
value={this.state.dateFormat}
onChange={this.onTextInputChange.bind(this, 'dateFormat')}
bsSize="small"
placeholder="Date format string"
/>,
)}
</div>
</Popover>
{this.formRow(
'Number format',
'Optional d3 number format string',
'd3-format',
<FormControl
value={this.state.d3format}
onChange={this.onTextInputChange.bind(this, 'd3format')}
bsSize="small"
placeholder="Number format string"
/>,
)}
{this.state.colType === 'spark' &&
this.formRow(
'Date format',
'Optional d3 date format string',
'date-format',
<FormControl
value={this.state.dateFormat}
onChange={this.onTextInputChange.bind(this, 'dateFormat')}
bsSize="small"
placeholder="Date format string"
/>,
)}
</div>
);
}
@@ -313,13 +306,11 @@ export default class TimeSeriesColumnControl extends React.Component {
return (
<span>
{this.textSummary()}{' '}
<OverlayTrigger
container={document.body}
<Popover
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
content={this.renderPopover()}
title="Column Configuration"
>
<InfoTooltipWithTrigger
icon="edit"
@@ -327,7 +318,7 @@ export default class TimeSeriesColumnControl extends React.Component {
onClick={this.edit.bind(this)}
label="edit-ts-column"
/>
</OverlayTrigger>
</Popover>
</span>
);
}

View File

@@ -18,7 +18,7 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { Popover, OverlayTrigger } from 'react-bootstrap';
import Popover from 'src/common/components/Popover';
import { decimal2sexagesimal } from 'geolib';
import Label from 'src/components/Label';
@@ -83,9 +83,9 @@ export default class ViewportControl extends React.Component {
renderPopover() {
return (
<Popover id={`filter-popover-${this.props.name}`} title="Viewport">
<div id={`filter-popover-${this.props.name}`}>
{PARAMS.map(ctrl => this.renderTextControl(ctrl))}
</Popover>
</div>
);
}
@@ -102,16 +102,15 @@ export default class ViewportControl extends React.Component {
return (
<div>
<ControlHeader {...this.props} />
<OverlayTrigger
<Popover
container={document.body}
trigger="click"
rootClose
ref="trigger"
placement="right"
overlay={this.renderPopover()}
content={this.renderPopover()}
title="Viewport"
>
<Label className="pointer">{this.renderLabel()}</Label>
</OverlayTrigger>
</Popover>
</div>
);
}