refactor: Migration of AnnotationLayerControl to TypeScript (#28346)
Co-authored-by: JUST.in DO IT <justin.park@airbnb.com> Co-authored-by: Diego Pucci <diegopucci.me@gmail.com>
This commit is contained in:
parent
0baac62099
commit
39f1b714a5
|
|
@ -249,7 +249,7 @@ export async function getChartDataRequest({
|
||||||
export function runAnnotationQuery({
|
export function runAnnotationQuery({
|
||||||
annotation,
|
annotation,
|
||||||
timeout,
|
timeout,
|
||||||
formData = null,
|
formData,
|
||||||
key,
|
key,
|
||||||
isDashboardRequest = false,
|
isDashboardRequest = false,
|
||||||
force = false,
|
force = false,
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,26 @@
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { PureComponent } from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { List } from 'src/components';
|
import { List } from 'src/components';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { t, withTheme } from '@superset-ui/core';
|
import { PureComponent } from 'react';
|
||||||
|
import {
|
||||||
|
HandlerFunction,
|
||||||
|
JsonObject,
|
||||||
|
Payload,
|
||||||
|
QueryFormData,
|
||||||
|
SupersetTheme,
|
||||||
|
t,
|
||||||
|
withTheme,
|
||||||
|
} from '@superset-ui/core';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
|
import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
|
||||||
import { getChartKey } from 'src/explore/exploreUtils';
|
import { getChartKey } from 'src/explore/exploreUtils';
|
||||||
import { runAnnotationQuery } from 'src/components/Chart/chartAction';
|
import { runAnnotationQuery } from 'src/components/Chart/chartAction';
|
||||||
import CustomListItem from 'src/explore/components/controls/CustomListItem';
|
import CustomListItem from 'src/explore/components/controls/CustomListItem';
|
||||||
|
import { ChartState, ExplorePageState } from 'src/explore/types';
|
||||||
|
import { AnyAction } from 'redux';
|
||||||
|
import { ThunkDispatch } from 'redux-thunk';
|
||||||
import ControlPopover, {
|
import ControlPopover, {
|
||||||
getSectionContainerElement,
|
getSectionContainerElement,
|
||||||
} from '../ControlPopover/ControlPopover';
|
} from '../ControlPopover/ControlPopover';
|
||||||
|
|
@ -36,19 +46,37 @@ const AnnotationLayer = AsyncEsmComponent(
|
||||||
() => <div style={{ width: 450, height: 368 }} />,
|
() => <div style={{ width: 450, height: 368 }} />,
|
||||||
);
|
);
|
||||||
|
|
||||||
const propTypes = {
|
export interface Annotation {
|
||||||
colorScheme: PropTypes.string.isRequired,
|
name: string;
|
||||||
annotationError: PropTypes.object,
|
show?: boolean;
|
||||||
annotationQuery: PropTypes.object,
|
annotation: string;
|
||||||
vizType: PropTypes.string,
|
timeout: Date;
|
||||||
|
key: string;
|
||||||
|
formData: QueryFormData | null;
|
||||||
|
isDashboardRequest?: boolean;
|
||||||
|
force?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
validationErrors: PropTypes.array,
|
export interface Props {
|
||||||
name: PropTypes.string.isRequired,
|
colorScheme: string;
|
||||||
actions: PropTypes.object,
|
annotationError: Record<string, string>;
|
||||||
value: PropTypes.arrayOf(PropTypes.object),
|
annotationQuery: Record<string, AbortController>;
|
||||||
onChange: PropTypes.func,
|
vizType: string;
|
||||||
refreshAnnotationData: PropTypes.func,
|
validationErrors: JsonObject[];
|
||||||
};
|
name: string;
|
||||||
|
actions: {
|
||||||
|
setControlValue: HandlerFunction;
|
||||||
|
};
|
||||||
|
value: Annotation[];
|
||||||
|
onChange: (annotations: Annotation[]) => void;
|
||||||
|
refreshAnnotationData: (payload: Payload) => void;
|
||||||
|
theme: SupersetTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PopoverState {
|
||||||
|
popoverVisible: Record<number | string, boolean>;
|
||||||
|
addedAnnotationIndex: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
vizType: '',
|
vizType: '',
|
||||||
|
|
@ -57,9 +85,10 @@ const defaultProps = {
|
||||||
annotationQuery: {},
|
annotationQuery: {},
|
||||||
onChange: () => {},
|
onChange: () => {},
|
||||||
};
|
};
|
||||||
|
class AnnotationLayerControl extends PureComponent<Props, PopoverState> {
|
||||||
|
static defaultProps = defaultProps;
|
||||||
|
|
||||||
class AnnotationLayerControl extends PureComponent {
|
constructor(props: Props) {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
popoverVisible: {},
|
popoverVisible: {},
|
||||||
|
|
@ -75,7 +104,7 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
AnnotationLayer.preload();
|
AnnotationLayer.preload();
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
UNSAFE_componentWillReceiveProps(nextProps: Props) {
|
||||||
const { name, annotationError, validationErrors, value } = nextProps;
|
const { name, annotationError, validationErrors, value } = nextProps;
|
||||||
if (Object.keys(annotationError).length && !validationErrors.length) {
|
if (Object.keys(annotationError).length && !validationErrors.length) {
|
||||||
this.props.actions.setControlValue(
|
this.props.actions.setControlValue(
|
||||||
|
|
@ -89,9 +118,12 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addAnnotationLayer(originalAnnotation, newAnnotation) {
|
addAnnotationLayer = (
|
||||||
|
originalAnnotation: Annotation | null,
|
||||||
|
newAnnotation: Annotation,
|
||||||
|
) => {
|
||||||
let annotations = this.props.value;
|
let annotations = this.props.value;
|
||||||
if (annotations.includes(originalAnnotation)) {
|
if (originalAnnotation && annotations.includes(originalAnnotation)) {
|
||||||
annotations = annotations.map(anno =>
|
annotations = annotations.map(anno =>
|
||||||
anno === originalAnnotation ? newAnnotation : anno,
|
anno === originalAnnotation ? newAnnotation : anno,
|
||||||
);
|
);
|
||||||
|
|
@ -106,15 +138,15 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onChange(annotations);
|
this.props.onChange(annotations);
|
||||||
}
|
};
|
||||||
|
|
||||||
handleVisibleChange(visible, popoverKey) {
|
handleVisibleChange = (visible: boolean, popoverKey: number | string) => {
|
||||||
this.setState(prevState => ({
|
this.setState(prevState => ({
|
||||||
popoverVisible: { ...prevState.popoverVisible, [popoverKey]: visible },
|
popoverVisible: { ...prevState.popoverVisible, [popoverKey]: visible },
|
||||||
}));
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
removeAnnotationLayer(annotation) {
|
removeAnnotationLayer(annotation: Annotation | null) {
|
||||||
const annotations = this.props.value.filter(anno => anno !== annotation);
|
const annotations = this.props.value.filter(anno => anno !== annotation);
|
||||||
// So scrollbar doesnt get stuck on hidden
|
// So scrollbar doesnt get stuck on hidden
|
||||||
const element = getSectionContainerElement();
|
const element = getSectionContainerElement();
|
||||||
|
|
@ -124,17 +156,21 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
this.props.onChange(annotations);
|
this.props.onChange(annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPopover(popoverKey, annotation, error) {
|
renderPopover = (
|
||||||
|
popoverKey: number | string,
|
||||||
|
annotation: Annotation | null,
|
||||||
|
error: string,
|
||||||
|
) => {
|
||||||
const id = annotation?.name || '_new';
|
const id = annotation?.name || '_new';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={`annotation-pop-${id}`} data-test="popover-content">
|
<div id={`annotation-pop-${id}`} data-test="popover-content">
|
||||||
<AnnotationLayer
|
<AnnotationLayer
|
||||||
{...annotation}
|
{...(annotation || {})}
|
||||||
error={error}
|
error={error}
|
||||||
colorScheme={this.props.colorScheme}
|
colorScheme={this.props.colorScheme}
|
||||||
vizType={this.props.vizType}
|
vizType={this.props.vizType}
|
||||||
addAnnotationLayer={newAnnotation =>
|
addAnnotationLayer={(newAnnotation: Annotation) =>
|
||||||
this.addAnnotationLayer(annotation, newAnnotation)
|
this.addAnnotationLayer(annotation, newAnnotation)
|
||||||
}
|
}
|
||||||
removeAnnotationLayer={() => this.removeAnnotationLayer(annotation)}
|
removeAnnotationLayer={() => this.removeAnnotationLayer(annotation)}
|
||||||
|
|
@ -145,9 +181,9 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
renderInfo(anno) {
|
renderInfo(anno: Annotation) {
|
||||||
const { annotationError, annotationQuery, theme } = this.props;
|
const { annotationError, annotationQuery, theme } = this.props;
|
||||||
if (annotationQuery[anno.name]) {
|
if (annotationQuery[anno.name]) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -175,8 +211,10 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { addedAnnotationIndex } = this.state;
|
const { addedAnnotationIndex } = this.state;
|
||||||
const addedAnnotation = this.props.value[addedAnnotationIndex];
|
const addedAnnotation =
|
||||||
|
addedAnnotationIndex !== null
|
||||||
|
? this.props.value[addedAnnotationIndex]
|
||||||
|
: null;
|
||||||
const annotations = this.props.value.map((anno, i) => (
|
const annotations = this.props.value.map((anno, i) => (
|
||||||
<ControlPopover
|
<ControlPopover
|
||||||
key={i}
|
key={i}
|
||||||
|
|
@ -202,15 +240,19 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
</CustomListItem>
|
</CustomListItem>
|
||||||
</ControlPopover>
|
</ControlPopover>
|
||||||
));
|
));
|
||||||
|
|
||||||
const addLayerPopoverKey = 'add';
|
const addLayerPopoverKey = 'add';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<List bordered css={theme => ({ borderRadius: theme.gridUnit })}>
|
<List bordered css={theme => ({ borderRadius: theme.gridUnit })}>
|
||||||
{annotations}
|
{annotations}
|
||||||
<ControlPopover
|
<ControlPopover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
content={this.renderPopover(addLayerPopoverKey, addedAnnotation)}
|
content={this.renderPopover(
|
||||||
|
addLayerPopoverKey,
|
||||||
|
addedAnnotation,
|
||||||
|
'',
|
||||||
|
)}
|
||||||
title={t('Add annotation layer')}
|
title={t('Add annotation layer')}
|
||||||
visible={this.state.popoverVisible[addLayerPopoverKey]}
|
visible={this.state.popoverVisible[addLayerPopoverKey]}
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
|
|
@ -232,27 +274,36 @@ class AnnotationLayerControl extends PureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnnotationLayerControl.propTypes = propTypes;
|
|
||||||
AnnotationLayerControl.defaultProps = defaultProps;
|
|
||||||
|
|
||||||
// Tried to hook this up through stores/control.jsx instead of using redux
|
// Tried to hook this up through stores/control.jsx instead of using redux
|
||||||
// directly, could not figure out how to get access to the color_scheme
|
// directly, could not figure out how to get access to the color_scheme
|
||||||
function mapStateToProps({ charts, explore }) {
|
function mapStateToProps({
|
||||||
|
charts,
|
||||||
|
explore,
|
||||||
|
}: Pick<ExplorePageState, 'charts' | 'explore'>) {
|
||||||
const chartKey = getChartKey(explore);
|
const chartKey = getChartKey(explore);
|
||||||
const chart = charts[chartKey] || charts[0] || {};
|
|
||||||
|
const defaultChartState: Partial<ChartState> = {
|
||||||
|
annotationError: {},
|
||||||
|
annotationQuery: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const chart =
|
||||||
|
chartKey && charts[chartKey] ? charts[chartKey] : defaultChartState;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
colorScheme: explore.controls?.color_scheme?.value,
|
colorScheme: explore.controls?.color_scheme?.value,
|
||||||
annotationError: chart.annotationError,
|
annotationError: chart.annotationError ?? {},
|
||||||
annotationQuery: chart.annotationQuery,
|
annotationQuery: chart.annotationQuery ?? {},
|
||||||
vizType: explore.controls.viz_type.value,
|
vizType: explore.controls?.viz_type.value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(
|
||||||
|
dispatch: ThunkDispatch<any, undefined, AnyAction>,
|
||||||
|
) {
|
||||||
return {
|
return {
|
||||||
refreshAnnotationData: annotationObj =>
|
refreshAnnotationData: (annotationObj: Annotation) =>
|
||||||
dispatch(runAnnotationQuery(annotationObj)),
|
dispatch(runAnnotationQuery(annotationObj)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue