mirror of
https://github.com/apache/superset.git
synced 2026-05-12 03:15:55 +00:00
committed by
GitHub
parent
3a81e6aee8
commit
d31958cbd2
@@ -21,6 +21,8 @@ import { render, screen } from 'spec/helpers/testing-library';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import TimeSeriesColumnControl from '.';
|
||||
|
||||
jest.mock('lodash/debounce', () => jest.fn(fn => fn));
|
||||
|
||||
test('renders with default props', () => {
|
||||
render(<TimeSeriesColumnControl />);
|
||||
expect(screen.getByText('Time series columns')).toBeInTheDocument();
|
||||
@@ -36,16 +38,6 @@ test('renders popover on edit', () => {
|
||||
expect(screen.getByText('Type')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('triggers onChange when type changes', () => {
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.click(screen.getByText('Select...'));
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByText('Time comparison'));
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('renders time comparison', () => {
|
||||
render(<TimeSeriesColumnControl colType="time" />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
@@ -82,23 +74,47 @@ test('renders period average', () => {
|
||||
expect(screen.getByText('Number format')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('triggers onChange when type changes', () => {
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.click(screen.getByText('Select...'));
|
||||
userEvent.click(screen.getByText('Time comparison'));
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ colType: 'time' }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when time lag changes', () => {
|
||||
const timeLag = '1';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="time" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
const timeLagInput = screen.getByPlaceholderText('Time Lag');
|
||||
userEvent.clear(timeLagInput);
|
||||
userEvent.type(timeLagInput, timeLag);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Time Lag'), '1');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ timeLag }));
|
||||
});
|
||||
|
||||
test('triggers onChange when color bounds changes', () => {
|
||||
const min = 1;
|
||||
const max = 5;
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="time" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
const minInput = screen.getByPlaceholderText('Min');
|
||||
const maxInput = screen.getByPlaceholderText('Max');
|
||||
userEvent.type(minInput, min.toString());
|
||||
userEvent.type(maxInput, max.toString());
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Min'), '1');
|
||||
userEvent.type(screen.getByPlaceholderText('Max'), '10');
|
||||
expect(onChange).toHaveBeenCalledTimes(3);
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenLastCalledWith(
|
||||
expect.objectContaining({ bounds: [min, max] }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when time type changes', () => {
|
||||
@@ -106,71 +122,102 @@ test('triggers onChange when time type changes', () => {
|
||||
render(<TimeSeriesColumnControl colType="time" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.click(screen.getByText('Select...'));
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByText('Difference'));
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ comparisonType: 'diff' }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when number format changes', () => {
|
||||
const numberFormatString = 'Test format';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="time" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.type(
|
||||
screen.getByPlaceholderText('Number format string'),
|
||||
numberFormatString,
|
||||
);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Number format string'), 'format');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ d3format: numberFormatString }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when width changes', () => {
|
||||
const width = '10';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.type(screen.getByPlaceholderText('Width'), width);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Width'), '10');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ width }));
|
||||
});
|
||||
|
||||
test('triggers onChange when height changes', () => {
|
||||
const height = '10';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.type(screen.getByPlaceholderText('Height'), height);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Height'), '10');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ height }));
|
||||
});
|
||||
|
||||
test('triggers onChange when time ratio changes', () => {
|
||||
const timeRatio = '10';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.type(screen.getByPlaceholderText('Time Ratio'), timeRatio);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Time Ratio'), '10');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(expect.objectContaining({ timeRatio }));
|
||||
});
|
||||
|
||||
test('triggers onChange when show Y-axis changes', () => {
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('checkbox'));
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ showYAxis: true }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when Y-axis bounds changes', () => {
|
||||
const min = 1;
|
||||
const max = 5;
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
const minInput = screen.getByPlaceholderText('Min');
|
||||
const maxInput = screen.getByPlaceholderText('Max');
|
||||
userEvent.type(minInput, min.toString());
|
||||
userEvent.clear(maxInput);
|
||||
userEvent.type(maxInput, max.toString());
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Min'), '1');
|
||||
userEvent.type(screen.getByPlaceholderText('Max'), '10');
|
||||
expect(onChange).toHaveBeenCalledTimes(3);
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ yAxisBounds: [min, max] }),
|
||||
);
|
||||
});
|
||||
|
||||
test('triggers onChange when date format changes', () => {
|
||||
const dateFormat = 'yy/MM/dd';
|
||||
const onChange = jest.fn();
|
||||
render(<TimeSeriesColumnControl colType="spark" onChange={onChange} />);
|
||||
userEvent.click(screen.getByRole('button'));
|
||||
userEvent.type(screen.getByPlaceholderText('Date format string'), dateFormat);
|
||||
expect(onChange).not.toHaveBeenCalled();
|
||||
userEvent.type(screen.getByPlaceholderText('Date format string'), 'yy/MM/dd');
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
userEvent.click(screen.getByRole('button', { name: 'Save' }));
|
||||
expect(onChange).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ dateFormat }),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -19,11 +19,11 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Row, Col, Input } from 'src/common/components';
|
||||
import Button from 'src/components/Button';
|
||||
import Popover from 'src/components/Popover';
|
||||
import Select from 'src/components/Select';
|
||||
import { t, styled } from '@superset-ui/core';
|
||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||
|
||||
import BoundsControl from '../BoundsControl';
|
||||
import CheckboxControl from '../CheckboxControl';
|
||||
|
||||
@@ -76,6 +76,8 @@ const colTypeOptions = [
|
||||
|
||||
const StyledRow = styled(Row)`
|
||||
margin-top: ${({ theme }) => theme.gridUnit * 2}px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
const StyledCol = styled(Col)`
|
||||
@@ -88,10 +90,27 @@ const StyledTooltip = styled(InfoTooltipWithTrigger)`
|
||||
color: ${({ theme }) => theme.colors.grayscale.light1};
|
||||
`;
|
||||
|
||||
const ButtonBar = styled.div`
|
||||
margin-top: ${({ theme }) => theme.gridUnit * 5}px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
`;
|
||||
|
||||
export default class TimeSeriesColumnControl extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const state = {
|
||||
|
||||
this.onSave = this.onSave.bind(this);
|
||||
this.onClose = this.onClose.bind(this);
|
||||
this.resetState = this.resetState.bind(this);
|
||||
this.initialState = this.initialState.bind(this);
|
||||
this.onPopoverVisibleChange = this.onPopoverVisibleChange.bind(this);
|
||||
|
||||
this.state = this.initialState();
|
||||
}
|
||||
|
||||
initialState() {
|
||||
return {
|
||||
label: this.props.label,
|
||||
tooltip: this.props.tooltip,
|
||||
colType: this.props.colType,
|
||||
@@ -105,57 +124,73 @@ export default class TimeSeriesColumnControl extends React.Component {
|
||||
bounds: this.props.bounds,
|
||||
d3format: this.props.d3format,
|
||||
dateFormat: this.props.dateFormat,
|
||||
popoverVisible: false,
|
||||
};
|
||||
delete state.onChange;
|
||||
this.state = state;
|
||||
this.onChange = this.onChange.bind(this);
|
||||
}
|
||||
|
||||
onChange() {
|
||||
resetState() {
|
||||
const initialState = this.initialState();
|
||||
this.setState({ ...initialState });
|
||||
}
|
||||
|
||||
onSave() {
|
||||
this.props.onChange(this.state);
|
||||
this.setState({ popoverVisible: false });
|
||||
}
|
||||
|
||||
onClose() {
|
||||
this.resetState();
|
||||
}
|
||||
|
||||
onSelectChange(attr, opt) {
|
||||
this.setState({ [attr]: opt.value }, this.onChange);
|
||||
this.setState({ [attr]: opt.value });
|
||||
}
|
||||
|
||||
onTextInputChange(attr, event) {
|
||||
this.setState({ [attr]: event.target.value }, this.onChange);
|
||||
this.setState({ [attr]: event.target.value });
|
||||
}
|
||||
|
||||
onCheckboxChange(attr, value) {
|
||||
this.setState({ [attr]: value }, this.onChange);
|
||||
this.setState({ [attr]: value });
|
||||
}
|
||||
|
||||
onBoundsChange(bounds) {
|
||||
this.setState({ bounds }, this.onChange);
|
||||
this.setState({ bounds });
|
||||
}
|
||||
|
||||
onPopoverVisibleChange(popoverVisible) {
|
||||
if (popoverVisible) {
|
||||
this.setState({ popoverVisible });
|
||||
} else {
|
||||
this.resetState();
|
||||
}
|
||||
}
|
||||
|
||||
onYAxisBoundsChange(yAxisBounds) {
|
||||
this.setState({ yAxisBounds }, this.onChange);
|
||||
this.setState({ yAxisBounds });
|
||||
}
|
||||
|
||||
textSummary() {
|
||||
return `${this.state.label}`;
|
||||
return `${this.props.label}`;
|
||||
}
|
||||
|
||||
formRow(label, tooltip, ttLabel, control) {
|
||||
return (
|
||||
<StyledRow>
|
||||
<StyledCol xs={24} md={10}>
|
||||
<StyledCol xs={24} md={11}>
|
||||
{label}
|
||||
<StyledTooltip placement="top" tooltip={tooltip} label={ttLabel} />
|
||||
</StyledCol>
|
||||
<StyledCol xs={24} md={14}>
|
||||
<Col xs={24} md={13}>
|
||||
{control}
|
||||
</StyledCol>
|
||||
</Col>
|
||||
</StyledRow>
|
||||
);
|
||||
}
|
||||
|
||||
renderPopover() {
|
||||
return (
|
||||
<div id="ts-col-popo" style={{ width: 300 }}>
|
||||
<div id="ts-col-popo" style={{ width: 320 }}>
|
||||
{this.formRow(
|
||||
'Label',
|
||||
'The column header label',
|
||||
@@ -297,6 +332,19 @@ export default class TimeSeriesColumnControl extends React.Component {
|
||||
placeholder="Date format string"
|
||||
/>,
|
||||
)}
|
||||
<ButtonBar>
|
||||
<Button buttonSize="small" onClick={this.onClose} cta>
|
||||
{t('Close')}
|
||||
</Button>
|
||||
<Button
|
||||
buttonStyle="primary"
|
||||
buttonSize="small"
|
||||
onClick={this.onSave}
|
||||
cta
|
||||
>
|
||||
{t('Save')}
|
||||
</Button>
|
||||
</ButtonBar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -310,6 +358,8 @@ export default class TimeSeriesColumnControl extends React.Component {
|
||||
placement="right"
|
||||
content={this.renderPopover()}
|
||||
title="Column Configuration"
|
||||
visible={this.state.popoverVisible}
|
||||
onVisibleChange={this.onPopoverVisibleChange}
|
||||
>
|
||||
<InfoTooltipWithTrigger
|
||||
icon="edit"
|
||||
|
||||
Reference in New Issue
Block a user