From 3311128c5e6c5de2ea5d6a2dfeb01ea3179e9af8 Mon Sep 17 00:00:00 2001 From: "Michael S. Molina" <70410625+michael-s-molina@users.noreply.github.com> Date: Wed, 20 Jul 2022 17:03:19 -0300 Subject: [PATCH] fix: Reverts #20749 and #20645 (#20796) * Revert "fix: Error when saving datasource from Explore (#20749)" This reverts commit 92f3621c754a4f3ddb99285aad273296be26567e. * Revert "refactor: Unify shared datasources reducers and actions (#20645)" This reverts commit 2a705406e1883834bb6696c1585ef65f787ce7b3. --- .../superset-ui-chart-controls/src/types.ts | 3 - .../spec/helpers/reducerIndex.ts | 2 +- .../src/components/Chart/chartReducer.ts | 4 +- .../src/dashboard/actions/dashboardState.js | 2 +- .../datasources.ts} | 40 +++++++-- .../FiltersConfigForm/utils.ts | 4 +- superset-frontend/src/dashboard/constants.ts | 4 +- .../src/dashboard/containers/Dashboard.ts | 2 +- .../dashboard/containers/DashboardPage.tsx | 2 +- .../src/dashboard/reducers/datasources.ts | 43 ++++++++++ superset-frontend/src/dashboard/types.ts | 8 +- .../actions/datasourcesActions.test.ts | 85 +++++++++++++++++++ .../actions/datasourcesActions.ts} | 51 +++++------ .../src/explore/actions/exploreActions.ts | 21 ----- .../explore/actions/hydrateExplore.test.ts | 3 + .../src/explore/actions/hydrateExplore.ts | 12 +-- .../components/ExploreViewContainer/index.jsx | 4 +- .../reducers/datasourcesReducer.ts} | 29 +++---- .../src/explore/reducers/exploreReducer.js | 13 --- .../src/hooks/apiResources/dashboards.ts | 5 +- superset-frontend/src/views/store.ts | 33 ++++++- 21 files changed, 259 insertions(+), 111 deletions(-) rename superset-frontend/src/dashboard/{util/fetchDatasourceMetadata.ts => actions/datasources.ts} (57%) create mode 100644 superset-frontend/src/dashboard/reducers/datasources.ts create mode 100644 superset-frontend/src/explore/actions/datasourcesActions.test.ts rename superset-frontend/src/{datasource/actions.ts => explore/actions/datasourcesActions.ts} (52%) rename superset-frontend/src/{datasource/reducer.ts => explore/reducers/datasourcesReducer.ts} (68%) diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts index e5e1c24a7..9c3a110fe 100644 --- a/superset-frontend/packages/superset-ui-chart-controls/src/types.ts +++ b/superset-frontend/packages/superset-ui-chart-controls/src/types.ts @@ -28,7 +28,6 @@ import type { QueryFormData, QueryFormMetric, QueryResponse, - GenericDataType, } from '@superset-ui/core'; import { sharedControls } from './shared-controls'; import sharedControlComponents from './shared-controls/components'; @@ -67,7 +66,6 @@ export interface Dataset { id: number; type: DatasourceType; columns: ColumnMeta[]; - column_types?: GenericDataType[]; metrics: Metric[]; column_format: Record; verbose_map: Record; @@ -81,7 +79,6 @@ export interface Dataset { description: string | null; uid?: string; owners?: Owner[]; - table_name?: string; } export interface ControlPanelState { diff --git a/superset-frontend/spec/helpers/reducerIndex.ts b/superset-frontend/spec/helpers/reducerIndex.ts index 52e49e741..edfaf7bb5 100644 --- a/superset-frontend/spec/helpers/reducerIndex.ts +++ b/superset-frontend/spec/helpers/reducerIndex.ts @@ -22,7 +22,7 @@ import dashboardInfo from 'src/dashboard/reducers/dashboardInfo'; import dashboardState from 'src/dashboard/reducers/dashboardState'; import dashboardFilters from 'src/dashboard/reducers/dashboardFilters'; import nativeFilters from 'src/dashboard/reducers/nativeFilters'; -import datasources from 'src/datasource/reducer'; +import datasources from 'src/dashboard/reducers/datasources'; import sliceEntities from 'src/dashboard/reducers/sliceEntities'; import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout'; import messageToasts from 'src/components/MessageToasts/reducers'; diff --git a/superset-frontend/src/components/Chart/chartReducer.ts b/superset-frontend/src/components/Chart/chartReducer.ts index 3f15ab56e..11b498290 100644 --- a/superset-frontend/src/components/Chart/chartReducer.ts +++ b/superset-frontend/src/components/Chart/chartReducer.ts @@ -19,7 +19,7 @@ /* eslint camelcase: 0 */ import { t } from '@superset-ui/core'; import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate'; -import { DatasourcesActionType } from 'src/datasource/actions'; +import { DatasourcesAction } from 'src/dashboard/actions/datasources'; import { ChartState } from 'src/explore/types'; import { getFormDataFromControls } from 'src/explore/controlUtils'; import { HYDRATE_EXPLORE } from 'src/explore/actions/hydrateExplore'; @@ -198,7 +198,7 @@ export default function chartReducer( if (action.type === HYDRATE_DASHBOARD || action.type === HYDRATE_EXPLORE) { return { ...action.data.charts }; } - if (action.type === DatasourcesActionType.SET_DATASOURCES) { + if (action.type === DatasourcesAction.SET_DATASOURCES) { return Object.fromEntries( Object.entries(charts).map(([chartId, chart]) => [ chartId, diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js index fa58336eb..1b9224a3d 100644 --- a/superset-frontend/src/dashboard/actions/dashboardState.js +++ b/superset-frontend/src/dashboard/actions/dashboardState.js @@ -43,13 +43,13 @@ import serializeFilterScopes from 'src/dashboard/util/serializeFilterScopes'; import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters'; import { safeStringify } from 'src/utils/safeStringify'; import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags'; -import { fetchDatasourceMetadata } from 'src/dashboard/util/fetchDatasourceMetadata'; import { UPDATE_COMPONENTS_PARENTS_LIST } from './dashboardLayout'; import { setChartConfiguration, dashboardInfoChanged, SET_CHART_CONFIG_COMPLETE, } from './dashboardInfo'; +import { fetchDatasourceMetadata } from './datasources'; import { addFilter, removeFilter, diff --git a/superset-frontend/src/dashboard/util/fetchDatasourceMetadata.ts b/superset-frontend/src/dashboard/actions/datasources.ts similarity index 57% rename from superset-frontend/src/dashboard/util/fetchDatasourceMetadata.ts rename to superset-frontend/src/dashboard/actions/datasources.ts index a70972a89..42004272c 100644 --- a/superset-frontend/src/dashboard/util/fetchDatasourceMetadata.ts +++ b/superset-frontend/src/dashboard/actions/datasources.ts @@ -18,9 +18,39 @@ */ import { Dispatch } from 'redux'; import { SupersetClient } from '@superset-ui/core'; -import { Dataset } from '@superset-ui/chart-controls'; -import { RootState } from 'src/dashboard/types'; -import { setDatasource } from 'src/datasource/actions'; +import { Datasource, RootState } from 'src/dashboard/types'; + +// update datasources index for Dashboard +export enum DatasourcesAction { + SET_DATASOURCES = 'SET_DATASOURCES', + SET_DATASOURCE = 'SET_DATASOURCE', +} + +export type DatasourcesActionPayload = + | { + type: DatasourcesAction.SET_DATASOURCES; + datasources: Datasource[] | null; + } + | { + type: DatasourcesAction.SET_DATASOURCE; + key: Datasource['uid']; + datasource: Datasource; + }; + +export function setDatasources(datasources: Datasource[] | null) { + return { + type: DatasourcesAction.SET_DATASOURCES, + datasources, + }; +} + +export function setDatasource(datasource: Datasource, key: string) { + return { + type: DatasourcesAction.SET_DATASOURCE, + key, + datasource, + }; +} export function fetchDatasourceMetadata(key: string) { return (dispatch: Dispatch, getState: () => RootState) => { @@ -28,11 +58,11 @@ export function fetchDatasourceMetadata(key: string) { const datasource = datasources[key]; if (datasource) { - return dispatch(setDatasource(datasource)); + return dispatch(setDatasource(datasource, key)); } return SupersetClient.get({ endpoint: `/superset/fetch_datasource_metadata?datasourceKey=${key}`, - }).then(({ json }) => dispatch(setDatasource(json as Dataset))); + }).then(({ json }) => dispatch(setDatasource(json as Datasource, key))); }; } diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts index 1d13d0606..2a0b7fcad 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/utils.ts @@ -88,7 +88,9 @@ export const datasetToSelectOption = ( // TODO: add column_types field to Dataset // We return true if column_types is undefined or empty as a precaution against backend failing to return column_types -export const hasTemporalColumns = (dataset: Dataset) => { +export const hasTemporalColumns = ( + dataset: Dataset & { column_types: GenericDataType[] }, +) => { const columnTypes = ensureIsArray(dataset?.column_types); return ( columnTypes.length === 0 || columnTypes.includes(GenericDataType.TEMPORAL) diff --git a/superset-frontend/src/dashboard/constants.ts b/superset-frontend/src/dashboard/constants.ts index dc1a28ea6..ab9d9b596 100644 --- a/superset-frontend/src/dashboard/constants.ts +++ b/superset-frontend/src/dashboard/constants.ts @@ -1,6 +1,6 @@ /* eslint-disable import/prefer-default-export */ import { DatasourceType } from '@superset-ui/core'; -import { Dataset } from '@superset-ui/chart-controls'; +import { Datasource } from 'src/dashboard/types'; /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -19,7 +19,7 @@ import { Dataset } from '@superset-ui/chart-controls'; * specific language governing permissions and limitations * under the License. */ -export const PLACEHOLDER_DATASOURCE: Dataset = { +export const PLACEHOLDER_DATASOURCE: Datasource = { id: 0, type: DatasourceType.Table, uid: '_placeholder_', diff --git a/superset-frontend/src/dashboard/containers/Dashboard.ts b/superset-frontend/src/dashboard/containers/Dashboard.ts index 093078262..647d774f4 100644 --- a/superset-frontend/src/dashboard/containers/Dashboard.ts +++ b/superset-frontend/src/dashboard/containers/Dashboard.ts @@ -24,7 +24,7 @@ import { addSliceToDashboard, removeSliceFromDashboard, } from 'src/dashboard/actions/dashboardState'; -import { setDatasources } from 'src/datasource/actions'; +import { setDatasources } from 'src/dashboard/actions/datasources'; import { triggerQuery } from 'src/components/Chart/chartAction'; import { logEvent } from 'src/logger/actions'; diff --git a/superset-frontend/src/dashboard/containers/DashboardPage.tsx b/superset-frontend/src/dashboard/containers/DashboardPage.tsx index f21946307..27e17e0f5 100644 --- a/superset-frontend/src/dashboard/containers/DashboardPage.tsx +++ b/superset-frontend/src/dashboard/containers/DashboardPage.tsx @@ -36,7 +36,7 @@ import { useDashboardDatasets, } from 'src/hooks/apiResources'; import { hydrateDashboard } from 'src/dashboard/actions/hydrate'; -import { setDatasources } from 'src/datasource/actions'; +import { setDatasources } from 'src/dashboard/actions/datasources'; import injectCustomCss from 'src/dashboard/util/injectCustomCss'; import setupPlugins from 'src/setup/setupPlugins'; import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes'; diff --git a/superset-frontend/src/dashboard/reducers/datasources.ts b/superset-frontend/src/dashboard/reducers/datasources.ts new file mode 100644 index 000000000..864641645 --- /dev/null +++ b/superset-frontend/src/dashboard/reducers/datasources.ts @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { keyBy } from 'lodash'; +import { DatasourcesState } from 'src/dashboard/types'; +import { + DatasourcesActionPayload, + DatasourcesAction, +} from '../actions/datasources'; + +export default function datasourcesReducer( + datasources: DatasourcesState | undefined, + action: DatasourcesActionPayload, +) { + if (action.type === DatasourcesAction.SET_DATASOURCES) { + return { + ...datasources, + ...keyBy(action.datasources, 'uid'), + }; + } + if (action.type === DatasourcesAction.SET_DATASOURCE) { + return { + ...datasources, + [action.key]: action.datasource, + }; + } + return datasources || {}; +} diff --git a/superset-frontend/src/dashboard/types.ts b/superset-frontend/src/dashboard/types.ts index 3d60b1599..160d62564 100644 --- a/superset-frontend/src/dashboard/types.ts +++ b/superset-frontend/src/dashboard/types.ts @@ -20,6 +20,7 @@ import { ChartProps, DataMaskStateWithId, ExtraFormData, + GenericDataType, JsonObject, NativeFiltersState, } from '@superset-ui/core'; @@ -83,8 +84,13 @@ export type DashboardInfo = { export type ChartsState = { [key: string]: Chart }; +export type Datasource = Dataset & { + uid: string; + column_types: GenericDataType[]; + table_name: string; +}; export type DatasourcesState = { - [key: string]: Dataset; + [key: string]: Datasource; }; /** Root state of redux */ diff --git a/superset-frontend/src/explore/actions/datasourcesActions.test.ts b/superset-frontend/src/explore/actions/datasourcesActions.test.ts new file mode 100644 index 000000000..a51d8576f --- /dev/null +++ b/superset-frontend/src/explore/actions/datasourcesActions.test.ts @@ -0,0 +1,85 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { DatasourceType } from '@superset-ui/core'; +import { + setDatasource, + changeDatasource, +} from 'src/explore/actions/datasourcesActions'; +import datasourcesReducer from '../reducers/datasourcesReducer'; +import { updateFormDataByDatasource } from './exploreActions'; + +const CURRENT_DATASOURCE = { + id: 1, + uid: '1__table', + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '__timestamp', + // eg. ['["ds", true]', 'ds [asc]'] + datasource_name: 'test datasource', + description: null, +}; + +const NEW_DATASOURCE = { + id: 2, + type: DatasourceType.Table, + columns: [], + metrics: [], + column_format: {}, + verbose_map: {}, + main_dttm_col: '__timestamp', + // eg. ['["ds", true]', 'ds [asc]'] + datasource_name: 'test datasource', + description: null, +}; + +const defaultDatasourcesReducerState = { + [CURRENT_DATASOURCE.uid]: CURRENT_DATASOURCE, +}; + +test('sets new datasource', () => { + const newState = datasourcesReducer( + defaultDatasourcesReducerState, + setDatasource(NEW_DATASOURCE), + ); + expect(newState).toEqual({ + ...defaultDatasourcesReducerState, + '2__table': NEW_DATASOURCE, + }); +}); + +test('change datasource action', () => { + const dispatch = jest.fn(); + const getState = jest.fn(() => ({ + explore: { + datasource: CURRENT_DATASOURCE, + }, + })); + // ignore getState type check - we dont need explore.datasource field for this test + // @ts-ignore + changeDatasource(NEW_DATASOURCE)(dispatch, getState); + expect(dispatch).toHaveBeenCalledTimes(2); + expect(dispatch).toHaveBeenNthCalledWith(1, setDatasource(NEW_DATASOURCE)); + expect(dispatch).toHaveBeenNthCalledWith( + 2, + updateFormDataByDatasource(CURRENT_DATASOURCE, NEW_DATASOURCE), + ); +}); diff --git a/superset-frontend/src/datasource/actions.ts b/superset-frontend/src/explore/actions/datasourcesActions.ts similarity index 52% rename from superset-frontend/src/datasource/actions.ts rename to superset-frontend/src/explore/actions/datasourcesActions.ts index 2a5a2ce48..4fc3bce96 100644 --- a/superset-frontend/src/datasource/actions.ts +++ b/superset-frontend/src/explore/actions/datasourcesActions.ts @@ -16,39 +16,34 @@ * specific language governing permissions and limitations * under the License. */ + +import { Dispatch } from 'redux'; import { Dataset } from '@superset-ui/chart-controls'; +import { updateFormDataByDatasource } from './exploreActions'; +import { ExplorePageState } from '../types'; -export enum DatasourcesActionType { - INIT_DATASOURCES = 'INIT_DATASOURCES', - SET_DATASOURCE = 'SET_DATASOURCE', - SET_DATASOURCES = 'SET_DATASOURCES', +export const SET_DATASOURCE = 'SET_DATASOURCE'; +export interface SetDatasource { + type: string; + datasource: Dataset; } - -export type DatasourcesAction = - | { - type: DatasourcesActionType.INIT_DATASOURCES; - datasources: { [key: string]: Dataset }; - } - | { - type: DatasourcesActionType.SET_DATASOURCES; - datasources: Dataset[] | null; - } - | { - type: DatasourcesActionType.SET_DATASOURCE; - datasource: Dataset; - }; - -export function initDatasources(datasources: { [key: string]: Dataset }) { - return { type: DatasourcesActionType.INIT_DATASOURCES, datasources }; -} - export function setDatasource(datasource: Dataset) { - return { type: DatasourcesActionType.SET_DATASOURCE, datasource }; + return { type: SET_DATASOURCE, datasource }; } -export function setDatasources(datasources: Dataset[] | null) { - return { - type: DatasourcesActionType.SET_DATASOURCES, - datasources, +export function changeDatasource(newDatasource: Dataset) { + return function (dispatch: Dispatch, getState: () => ExplorePageState) { + const { + explore: { datasource: prevDatasource }, + } = getState(); + dispatch(setDatasource(newDatasource)); + dispatch(updateFormDataByDatasource(prevDatasource, newDatasource)); }; } + +export const datasourcesActions = { + setDatasource, + changeDatasource, +}; + +export type AnyDatasourcesAction = SetDatasource; diff --git a/superset-frontend/src/explore/actions/exploreActions.ts b/superset-frontend/src/explore/actions/exploreActions.ts index f393c7485..2ec0d086c 100644 --- a/superset-frontend/src/explore/actions/exploreActions.ts +++ b/superset-frontend/src/explore/actions/exploreActions.ts @@ -25,8 +25,6 @@ import { toastActions, } from 'src/components/MessageToasts/actions'; import { Slice } from 'src/types/Chart'; -import { setDatasource } from 'src/datasource/actions'; -import { ExplorePageState } from 'src/explore/types'; const FAVESTAR_BASE_URL = '/superset/favstar/slice'; @@ -142,24 +140,6 @@ export function setForceQuery(force: boolean) { }; } -export const SAVE_DATASOURCE = 'SAVE_DATASOURCE'; -export function saveDatasource(datasource: Dataset) { - return function (dispatch: Dispatch) { - dispatch(setDatasource(datasource)); - dispatch({ type: SAVE_DATASOURCE, datasource }); - }; -} - -export function changeDatasource(newDatasource: Dataset) { - return function (dispatch: Dispatch, getState: () => ExplorePageState) { - const { - explore: { datasource: prevDatasource }, - } = getState(); - dispatch(setDatasource(newDatasource)); - dispatch(updateFormDataByDatasource(prevDatasource, newDatasource)); - }; -} - export const exploreActions = { ...toastActions, fetchDatasourcesStarted, @@ -173,7 +153,6 @@ export const exploreActions = { createNewSlice, sliceUpdated, setForceQuery, - changeDatasource, }; export type ExploreActions = typeof exploreActions; diff --git a/superset-frontend/src/explore/actions/hydrateExplore.test.ts b/superset-frontend/src/explore/actions/hydrateExplore.test.ts index 3b3963f9f..9cc7b883e 100644 --- a/superset-frontend/src/explore/actions/hydrateExplore.test.ts +++ b/superset-frontend/src/explore/actions/hydrateExplore.test.ts @@ -64,6 +64,9 @@ test('creates hydrate action from initial data', () => { lastRendered: 0, }, }, + datasources: { + '8__table': exploreInitialData.dataset, + }, saveModal: { dashboards: [], saveModalAlert: null, diff --git a/superset-frontend/src/explore/actions/hydrateExplore.ts b/superset-frontend/src/explore/actions/hydrateExplore.ts index b16ac30a7..2479a8c97 100644 --- a/superset-frontend/src/explore/actions/hydrateExplore.ts +++ b/superset-frontend/src/explore/actions/hydrateExplore.ts @@ -35,7 +35,6 @@ import { getDatasourceUid } from 'src/utils/getDatasourceUid'; import { getUrlParam } from 'src/utils/urlUtils'; import { URL_PARAMS } from 'src/constants'; import { findPermission } from 'src/utils/findPermission'; -import { initDatasources } from 'src/datasource/actions'; export const HYDRATE_EXPLORE = 'HYDRATE_EXPLORE'; export const hydrateExplore = @@ -121,13 +120,6 @@ export const hydrateExplore = lastRendered: 0, }; - dispatch( - initDatasources({ - ...datasources, - [getDatasourceUid(initialDatasource)]: initialDatasource, - }), - ); - return dispatch({ type: HYDRATE_EXPLORE, data: { @@ -135,6 +127,10 @@ export const hydrateExplore = ...charts, [chartKey]: chart, }, + datasources: { + ...datasources, + [getDatasourceUid(initialDatasource)]: initialDatasource, + }, saveModal: { dashboards: [], saveModalAlert: null, diff --git a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx index ab4e0c91a..82443fc3a 100644 --- a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx +++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx @@ -46,10 +46,11 @@ import { import { getUrlParam } from 'src/utils/urlUtils'; import cx from 'classnames'; import * as chartActions from 'src/components/Chart/chartAction'; -import { fetchDatasourceMetadata } from 'src/dashboard/util/fetchDatasourceMetadata'; +import { fetchDatasourceMetadata } from 'src/dashboard/actions/datasources'; import { chartPropShape } from 'src/dashboard/util/propShapes'; import { mergeExtraFormData } from 'src/dashboard/components/nativeFilters/utils'; import { postFormData, putFormData } from 'src/explore/exploreUtils/formData'; +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'; @@ -753,6 +754,7 @@ function mapStateToProps(state) { function mapDispatchToProps(dispatch) { const actions = { ...exploreActions, + ...datasourcesActions, ...saveModalActions, ...chartActions, ...logActions, diff --git a/superset-frontend/src/datasource/reducer.ts b/superset-frontend/src/explore/reducers/datasourcesReducer.ts similarity index 68% rename from superset-frontend/src/datasource/reducer.ts rename to superset-frontend/src/explore/reducers/datasourcesReducer.ts index 476ed750b..50393dbd2 100644 --- a/superset-frontend/src/datasource/reducer.ts +++ b/superset-frontend/src/explore/reducers/datasourcesReducer.ts @@ -16,32 +16,27 @@ * specific language governing permissions and limitations * under the License. */ -import { keyBy } from 'lodash'; +import { Dataset } from '@superset-ui/chart-controls'; import { getDatasourceUid } from 'src/utils/getDatasourceUid'; import { - DatasourcesAction, - DatasourcesActionType, -} from 'src/datasource/actions'; -import { Dataset } from '@superset-ui/chart-controls'; + AnyDatasourcesAction, + SET_DATASOURCE, +} from '../actions/datasourcesActions'; +import { HYDRATE_EXPLORE, HydrateExplore } from '../actions/hydrateExplore'; export default function datasourcesReducer( - datasources: { [key: string]: Dataset } | undefined, - action: DatasourcesAction, + // TODO: change type to include other datasource types + datasources: { [key: string]: Dataset }, + action: AnyDatasourcesAction | HydrateExplore, ) { - if (action.type === DatasourcesActionType.INIT_DATASOURCES) { - return { ...action.datasources }; - } - if (action.type === DatasourcesActionType.SET_DATASOURCES) { - return { - ...datasources, - ...keyBy(action.datasources, 'uid'), - }; - } - if (action.type === DatasourcesActionType.SET_DATASOURCE) { + if (action.type === SET_DATASOURCE) { return { ...datasources, [getDatasourceUid(action.datasource)]: action.datasource, }; } + if (action.type === HYDRATE_EXPLORE) { + return { ...(action as HydrateExplore).data.datasources }; + } return datasources || {}; } diff --git a/superset-frontend/src/explore/reducers/exploreReducer.js b/superset-frontend/src/explore/reducers/exploreReducer.js index 93743285c..f99ab9437 100644 --- a/superset-frontend/src/explore/reducers/exploreReducer.js +++ b/superset-frontend/src/explore/reducers/exploreReducer.js @@ -50,19 +50,6 @@ export default function exploreReducer(state = {}, action) { isDatasourceMetaLoading: true, }; }, - [actions.SAVE_DATASOURCE]() { - return { - ...state, - datasource: action.datasource, - controls: { - ...state.controls, - datasource: { - ...state.controls.datasource, - datasource: action.datasource, - }, - }, - }; - }, [actions.UPDATE_FORM_DATA_BY_DATASOURCE]() { const newFormData = { ...state.form_data }; const { prevDatasource, newDatasource } = action; diff --git a/superset-frontend/src/hooks/apiResources/dashboards.ts b/superset-frontend/src/hooks/apiResources/dashboards.ts index 7292194c7..b21cc668c 100644 --- a/superset-frontend/src/hooks/apiResources/dashboards.ts +++ b/superset-frontend/src/hooks/apiResources/dashboards.ts @@ -17,8 +17,7 @@ * under the License. */ -import { Dashboard, EmbeddedDashboard } from 'src/dashboard/types'; -import { Dataset } from '@superset-ui/chart-controls'; +import { Dashboard, Datasource, EmbeddedDashboard } from 'src/dashboard/types'; import { Chart } from 'src/types/Chart'; import { useApiV1Resource, useTransformedResource } from './apiResources'; @@ -43,7 +42,7 @@ export const useDashboardCharts = (idOrSlug: string | number) => // important: this endpoint only returns the fields in the dataset // that are necessary for rendering the given dashboard export const useDashboardDatasets = (idOrSlug: string | number) => - useApiV1Resource(`/api/v1/dashboard/${idOrSlug}/datasets`); + useApiV1Resource(`/api/v1/dashboard/${idOrSlug}/datasets`); export const useEmbeddedDashboard = (idOrSlug: string | number) => useApiV1Resource(`/api/v1/dashboard/${idOrSlug}/embedded`); diff --git a/superset-frontend/src/views/store.ts b/superset-frontend/src/views/store.ts index 284a8d966..251feeec5 100644 --- a/superset-frontend/src/views/store.ts +++ b/superset-frontend/src/views/store.ts @@ -33,17 +33,26 @@ import dashboardInfo from 'src/dashboard/reducers/dashboardInfo'; import dashboardState from 'src/dashboard/reducers/dashboardState'; import dashboardFilters from 'src/dashboard/reducers/dashboardFilters'; import nativeFilters from 'src/dashboard/reducers/nativeFilters'; -import datasources from 'src/datasource/reducer'; +import dashboardDatasources from 'src/dashboard/reducers/datasources'; import sliceEntities from 'src/dashboard/reducers/sliceEntities'; import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout'; import logger from 'src/middleware/loggerMiddleware'; import saveModal from 'src/explore/reducers/saveModalReducer'; import explore from 'src/explore/reducers/exploreReducer'; +import exploreDatasources from 'src/explore/reducers/datasourcesReducer'; +import { DatasourcesState } from 'src/dashboard/types'; +import { + DatasourcesActionPayload, + DatasourcesAction, +} from 'src/dashboard/actions/datasources'; import shortid from 'shortid'; import { BootstrapUser, UserWithPermissionsAndRoles, } from 'src/types/bootstrapTypes'; +import { AnyDatasourcesAction } from 'src/explore/actions/datasourcesActions'; +import { HydrateExplore } from 'src/explore/actions/hydrateExplore'; +import { Dataset } from '@superset-ui/chart-controls'; // Some reducers don't do anything, and redux is just used to reference the initial "state". // This may change later, as the client application takes on more responsibilities. @@ -72,6 +81,26 @@ const userReducer = ( return user; }; +// TODO: This reducer is a combination of the Dashboard and Explore reducers. +// The correct way of handling this is to unify the actions and reducers from both +// modules in shared files. This involves a big refactor to unify the parameter types +// and move files around. We should tackle this in a specific PR. +const CombinedDatasourceReducers = ( + datasources: DatasourcesState | undefined | { [key: string]: Dataset }, + action: DatasourcesActionPayload | AnyDatasourcesAction | HydrateExplore, +) => { + if (action.type === DatasourcesAction.SET_DATASOURCES) { + return dashboardDatasources( + datasources as DatasourcesState | undefined, + action as DatasourcesActionPayload, + ); + } + return exploreDatasources( + datasources as { [key: string]: Dataset }, + action as AnyDatasourcesAction | HydrateExplore, + ); +}; + // exported for tests export const rootReducer = combineReducers({ messageToasts: messageToastReducer, @@ -79,7 +108,7 @@ export const rootReducer = combineReducers({ user: userReducer, impressionId: noopReducer(shortid.generate()), charts, - datasources, + datasources: CombinedDatasourceReducers, dashboardInfo, dashboardFilters, dataMask,