mirror of
https://github.com/apache/superset.git
synced 2026-04-19 08:04:53 +00:00
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:
committed by
GitHub
parent
4208ca76e0
commit
901a42b1df
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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'}
|
||||
|
||||
<i
|
||||
className="fa fa-pencil"
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
</span>
|
||||
</OverlayTrigger>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
/>{' '}
|
||||
{t('Add Annotation Layer')}
|
||||
</ListGroupItem>
|
||||
</OverlayTrigger>
|
||||
</Popover>
|
||||
</ListGroup>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user