diff --git a/superset-frontend/src/components/Chart/chartAction.js b/superset-frontend/src/components/Chart/chartAction.js
index 8a9124818424f..f7008c9de37ba 100644
--- a/superset-frontend/src/components/Chart/chartAction.js
+++ b/superset-frontend/src/components/Chart/chartAction.js
@@ -249,7 +249,7 @@ export async function getChartDataRequest({
export function runAnnotationQuery({
annotation,
timeout,
- formData = null,
+ formData,
key,
isDashboardRequest = false,
force = false,
diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
similarity index 72%
rename from superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx
rename to superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
index 760717a3d9a11..7b77319c6d099 100644
--- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.jsx
+++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/index.tsx
@@ -16,16 +16,26 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { PureComponent } from 'react';
-import PropTypes from 'prop-types';
import { List } from 'src/components';
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 AsyncEsmComponent from 'src/components/AsyncEsmComponent';
import { getChartKey } from 'src/explore/exploreUtils';
import { runAnnotationQuery } from 'src/components/Chart/chartAction';
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, {
getSectionContainerElement,
} from '../ControlPopover/ControlPopover';
@@ -36,19 +46,37 @@ const AnnotationLayer = AsyncEsmComponent(
() =>
,
);
-const propTypes = {
- colorScheme: PropTypes.string.isRequired,
- annotationError: PropTypes.object,
- annotationQuery: PropTypes.object,
- vizType: PropTypes.string,
+export interface Annotation {
+ name: string;
+ show?: boolean;
+ annotation: string;
+ timeout: Date;
+ key: string;
+ formData: QueryFormData | null;
+ isDashboardRequest?: boolean;
+ force?: boolean;
+}
- validationErrors: PropTypes.array,
- name: PropTypes.string.isRequired,
- actions: PropTypes.object,
- value: PropTypes.arrayOf(PropTypes.object),
- onChange: PropTypes.func,
- refreshAnnotationData: PropTypes.func,
-};
+export interface Props {
+ colorScheme: string;
+ annotationError: Record;
+ annotationQuery: Record;
+ vizType: string;
+ validationErrors: JsonObject[];
+ name: string;
+ actions: {
+ setControlValue: HandlerFunction;
+ };
+ value: Annotation[];
+ onChange: (annotations: Annotation[]) => void;
+ refreshAnnotationData: (payload: Payload) => void;
+ theme: SupersetTheme;
+}
+
+export interface PopoverState {
+ popoverVisible: Record;
+ addedAnnotationIndex: number | null;
+}
const defaultProps = {
vizType: '',
@@ -57,9 +85,10 @@ const defaultProps = {
annotationQuery: {},
onChange: () => {},
};
+class AnnotationLayerControl extends PureComponent {
+ static defaultProps = defaultProps;
-class AnnotationLayerControl extends PureComponent {
- constructor(props) {
+ constructor(props: Props) {
super(props);
this.state = {
popoverVisible: {},
@@ -75,7 +104,7 @@ class AnnotationLayerControl extends PureComponent {
AnnotationLayer.preload();
}
- UNSAFE_componentWillReceiveProps(nextProps) {
+ UNSAFE_componentWillReceiveProps(nextProps: Props) {
const { name, annotationError, validationErrors, value } = nextProps;
if (Object.keys(annotationError).length && !validationErrors.length) {
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;
- if (annotations.includes(originalAnnotation)) {
+ if (originalAnnotation && annotations.includes(originalAnnotation)) {
annotations = annotations.map(anno =>
anno === originalAnnotation ? newAnnotation : anno,
);
@@ -106,15 +138,15 @@ class AnnotationLayerControl extends PureComponent {
});
this.props.onChange(annotations);
- }
+ };
- handleVisibleChange(visible, popoverKey) {
+ handleVisibleChange = (visible: boolean, popoverKey: number | string) => {
this.setState(prevState => ({
popoverVisible: { ...prevState.popoverVisible, [popoverKey]: visible },
}));
- }
+ };
- removeAnnotationLayer(annotation) {
+ removeAnnotationLayer(annotation: Annotation | null) {
const annotations = this.props.value.filter(anno => anno !== annotation);
// So scrollbar doesnt get stuck on hidden
const element = getSectionContainerElement();
@@ -124,17 +156,21 @@ class AnnotationLayerControl extends PureComponent {
this.props.onChange(annotations);
}
- renderPopover(popoverKey, annotation, error) {
+ renderPopover = (
+ popoverKey: number | string,
+ annotation: Annotation | null,
+ error: string,
+ ) => {
const id = annotation?.name || '_new';
return (
+ addAnnotationLayer={(newAnnotation: Annotation) =>
this.addAnnotationLayer(annotation, newAnnotation)
}
removeAnnotationLayer={() => this.removeAnnotationLayer(annotation)}
@@ -145,9 +181,9 @@ class AnnotationLayerControl extends PureComponent {
/>
);
- }
+ };
- renderInfo(anno) {
+ renderInfo(anno: Annotation) {
const { annotationError, annotationQuery, theme } = this.props;
if (annotationQuery[anno.name]) {
return (
@@ -175,8 +211,10 @@ class AnnotationLayerControl extends PureComponent {
render() {
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 addLayerPopoverKey = 'add';
+
return (
({ borderRadius: theme.gridUnit })}>
{annotations}
) {
const chartKey = getChartKey(explore);
- const chart = charts[chartKey] || charts[0] || {};
+
+ const defaultChartState: Partial = {
+ annotationError: {},
+ annotationQuery: {},
+ };
+
+ const chart =
+ chartKey && charts[chartKey] ? charts[chartKey] : defaultChartState;
return {
// eslint-disable-next-line camelcase
colorScheme: explore.controls?.color_scheme?.value,
- annotationError: chart.annotationError,
- annotationQuery: chart.annotationQuery,
- vizType: explore.controls.viz_type.value,
+ annotationError: chart.annotationError ?? {},
+ annotationQuery: chart.annotationQuery ?? {},
+ vizType: explore.controls?.viz_type.value,
};
}
-function mapDispatchToProps(dispatch) {
+function mapDispatchToProps(
+ dispatch: ThunkDispatch,
+) {
return {
- refreshAnnotationData: annotationObj =>
+ refreshAnnotationData: (annotationObj: Annotation) =>
dispatch(runAnnotationQuery(annotationObj)),
};
}