diff --git a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx index 66fb27886bc..a7450ed7b6f 100644 --- a/superset-frontend/src/explore/components/ControlPanelsContainer.tsx +++ b/superset-frontend/src/explore/components/ControlPanelsContainer.tsx @@ -95,7 +95,8 @@ const MATRIXIFY_INCOMPATIBLE_CHARTS = new Set([ export type ControlPanelsContainerProps = { exploreState: ExplorePageState['explore']; - actions: ExploreActions; + // Only setControlValue is used from actions in this component + actions: Pick; datasource_type: DatasourceType; chart: ChartState; controls: Record; diff --git a/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx b/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx index 84e3581215d..88f15855844 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx @@ -17,8 +17,15 @@ * under the License. */ /* eslint camelcase: 0 */ -import { memo, useCallback, useEffect, useMemo, useState } from 'react'; -import { bindActionCreators, Dispatch } from 'redux'; +import { + ComponentType, + memo, + useCallback, + useEffect, + useMemo, + useState, +} from 'react'; +import { bindActionCreators, Dispatch, ActionCreatorsMapObject } from 'redux'; import { connect } from 'react-redux'; import { useChangeEffect, @@ -28,8 +35,12 @@ import { QueryFormData, JsonObject, MatrixifyFormData, + DatasourceType, } from '@superset-ui/core'; -import { ControlStateMapping } from '@superset-ui/chart-controls'; +import { + ControlStateMapping, + ControlPanelState, +} from '@superset-ui/chart-controls'; import { t, styled, css, useTheme } from '@apache-superset/core/ui'; import { logging } from '@apache-superset/core'; import { debounce, isEqual, isObjectLike, omit, pick } from 'lodash'; @@ -62,6 +73,7 @@ import { datasourcesActions } from 'src/explore/actions/datasourcesActions'; import { mountExploreUrl } from 'src/explore/exploreUtils'; import { getFormDataFromControls } from 'src/explore/controlUtils'; import * as exploreActions from 'src/explore/actions/exploreActions'; +import { ExploreActions } from 'src/explore/actions/exploreActions'; import * as saveModalActions from 'src/explore/actions/saveModalActions'; import { useTabId } from 'src/hooks/useTabId'; import withToasts from 'src/components/MessageToasts/withToasts'; @@ -69,6 +81,7 @@ import { ChartState, Datasource, ExplorePageInitialData, + ExplorePageState, SaveActionType, } from 'src/explore/types'; import { Slice } from 'src/types/Chart'; @@ -311,7 +324,7 @@ interface OwnProps { interface StateProps { isDatasourceMetaLoading: boolean; datasource: Datasource; - datasource_type: string; + datasource_type: DatasourceType; datasourceId: number; dashboardId?: number; colorScheme?: string; @@ -337,19 +350,29 @@ interface StateProps { ownState?: JsonObject; impressionId: string; user: User; - exploreState: ExploreRootState['explore']; + exploreState: ExplorePageState['explore']; reports: JsonObject; metadata?: ExplorePageInitialData['metadata']; saveAction?: SaveActionType | null; isSaveModalVisible: boolean; } +// Combined actions type representing all action creators used in Explore +type CombinedExploreActions = typeof exploreActions & + typeof datasourcesActions & + typeof saveModalActions & + typeof chartActions & + typeof logActions; + +// Bound action creators type (what mapDispatchToProps actually returns) +type BoundActions = { + [K in keyof T]: T[K] extends (...args: infer A) => infer R + ? (...args: A) => R extends (...args: unknown[]) => infer R2 ? R2 : R + : T[K]; +}; + interface DispatchProps { - actions: typeof exploreActions & - typeof datasourcesActions & - typeof saveModalActions & - typeof chartActions & - typeof logActions; + actions: BoundActions; } type ExploreViewContainerProps = StateProps & DispatchProps & OwnProps; @@ -744,7 +767,10 @@ function ExploreViewContainer(props: ExploreViewContainerProps) { .filter(control => control.validationErrors?.includes(message)) .map(control => typeof control.label === 'function' - ? control.label(props.exploreState as any, control) + ? control.label( + props.exploreState as unknown as ControlPanelState, + control, + ) : control.label, ); return [matchingLabels, message]; @@ -787,7 +813,10 @@ function ExploreViewContainer(props: ExploreViewContainerProps) { .filter(control => control.validationErrors?.includes(message)) .map(control => typeof control.label === 'function' - ? control.label(props.exploreState as any, control) + ? control.label( + props.exploreState as unknown as ControlPanelState, + control, + ) : control.label, ); return [matchingLabels, message]; @@ -858,6 +887,7 @@ function ExploreViewContainer(props: ExploreViewContainerProps) { return ( + {/* eslint-disable @typescript-eslint/no-explicit-any -- DataSourcePanel uses narrower types that are compatible at runtime */} + {/* eslint-enable @typescript-eslint/no-explicit-any */} {isCollapsed ? (
, }; } +// withToasts HOC expects ComponentType, requiring type assertion +// The connected component properly handles StateProps & DispatchProps & OwnProps export default connect( mapStateToProps, mapDispatchToProps, -)(withToasts(memo(ExploreViewContainer)) as any); +)(withToasts(memo(ExploreViewContainer)) as ComponentType);