mirror of
https://github.com/apache/superset.git
synced 2024-09-06 13:57:40 -04:00
refactor: Unify shared datasources reducers and actions (#20645)
* refactor: Unify shared datasources reducers and actions
* Removes column_types
* Adjusts hydrateExplore
* Revert "Removes column_types"
This reverts commit 096bbf7826
.
* Fixes test
This commit is contained in:
parent
ec2eb3ddf8
commit
2a705406e1
@ -28,6 +28,7 @@ import type {
|
|||||||
QueryFormData,
|
QueryFormData,
|
||||||
QueryFormMetric,
|
QueryFormMetric,
|
||||||
QueryResponse,
|
QueryResponse,
|
||||||
|
GenericDataType,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
import { sharedControls } from './shared-controls';
|
import { sharedControls } from './shared-controls';
|
||||||
import sharedControlComponents from './shared-controls/components';
|
import sharedControlComponents from './shared-controls/components';
|
||||||
@ -66,6 +67,7 @@ export interface Dataset {
|
|||||||
id: number;
|
id: number;
|
||||||
type: DatasourceType;
|
type: DatasourceType;
|
||||||
columns: ColumnMeta[];
|
columns: ColumnMeta[];
|
||||||
|
column_types?: GenericDataType[];
|
||||||
metrics: Metric[];
|
metrics: Metric[];
|
||||||
column_format: Record<string, string>;
|
column_format: Record<string, string>;
|
||||||
verbose_map: Record<string, string>;
|
verbose_map: Record<string, string>;
|
||||||
@ -79,6 +81,7 @@ export interface Dataset {
|
|||||||
description: string | null;
|
description: string | null;
|
||||||
uid?: string;
|
uid?: string;
|
||||||
owners?: Owner[];
|
owners?: Owner[];
|
||||||
|
table_name?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ControlPanelState {
|
export interface ControlPanelState {
|
||||||
|
@ -22,7 +22,7 @@ import dashboardInfo from 'src/dashboard/reducers/dashboardInfo';
|
|||||||
import dashboardState from 'src/dashboard/reducers/dashboardState';
|
import dashboardState from 'src/dashboard/reducers/dashboardState';
|
||||||
import dashboardFilters from 'src/dashboard/reducers/dashboardFilters';
|
import dashboardFilters from 'src/dashboard/reducers/dashboardFilters';
|
||||||
import nativeFilters from 'src/dashboard/reducers/nativeFilters';
|
import nativeFilters from 'src/dashboard/reducers/nativeFilters';
|
||||||
import datasources from 'src/dashboard/reducers/datasources';
|
import datasources from 'src/datasource/reducer';
|
||||||
import sliceEntities from 'src/dashboard/reducers/sliceEntities';
|
import sliceEntities from 'src/dashboard/reducers/sliceEntities';
|
||||||
import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout';
|
import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout';
|
||||||
import messageToasts from 'src/components/MessageToasts/reducers';
|
import messageToasts from 'src/components/MessageToasts/reducers';
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
/* eslint camelcase: 0 */
|
/* eslint camelcase: 0 */
|
||||||
import { t } from '@superset-ui/core';
|
import { t } from '@superset-ui/core';
|
||||||
import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate';
|
import { HYDRATE_DASHBOARD } from 'src/dashboard/actions/hydrate';
|
||||||
import { DatasourcesAction } from 'src/dashboard/actions/datasources';
|
import { DatasourcesActionType } from 'src/datasource/actions';
|
||||||
import { ChartState } from 'src/explore/types';
|
import { ChartState } from 'src/explore/types';
|
||||||
import { getFormDataFromControls } from 'src/explore/controlUtils';
|
import { getFormDataFromControls } from 'src/explore/controlUtils';
|
||||||
import { HYDRATE_EXPLORE } from 'src/explore/actions/hydrateExplore';
|
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) {
|
if (action.type === HYDRATE_DASHBOARD || action.type === HYDRATE_EXPLORE) {
|
||||||
return { ...action.data.charts };
|
return { ...action.data.charts };
|
||||||
}
|
}
|
||||||
if (action.type === DatasourcesAction.SET_DATASOURCES) {
|
if (action.type === DatasourcesActionType.SET_DATASOURCES) {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(charts).map(([chartId, chart]) => [
|
Object.entries(charts).map(([chartId, chart]) => [
|
||||||
chartId,
|
chartId,
|
||||||
|
@ -43,13 +43,13 @@ import serializeFilterScopes from 'src/dashboard/util/serializeFilterScopes';
|
|||||||
import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters';
|
import { getActiveFilters } from 'src/dashboard/util/activeDashboardFilters';
|
||||||
import { safeStringify } from 'src/utils/safeStringify';
|
import { safeStringify } from 'src/utils/safeStringify';
|
||||||
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
import { FeatureFlag, isFeatureEnabled } from 'src/featureFlags';
|
||||||
|
import { fetchDatasourceMetadata } from 'src/dashboard/util/fetchDatasourceMetadata';
|
||||||
import { UPDATE_COMPONENTS_PARENTS_LIST } from './dashboardLayout';
|
import { UPDATE_COMPONENTS_PARENTS_LIST } from './dashboardLayout';
|
||||||
import {
|
import {
|
||||||
setChartConfiguration,
|
setChartConfiguration,
|
||||||
dashboardInfoChanged,
|
dashboardInfoChanged,
|
||||||
SET_CHART_CONFIG_COMPLETE,
|
SET_CHART_CONFIG_COMPLETE,
|
||||||
} from './dashboardInfo';
|
} from './dashboardInfo';
|
||||||
import { fetchDatasourceMetadata } from './datasources';
|
|
||||||
import {
|
import {
|
||||||
addFilter,
|
addFilter,
|
||||||
removeFilter,
|
removeFilter,
|
||||||
|
@ -88,9 +88,7 @@ export const datasetToSelectOption = (
|
|||||||
|
|
||||||
// TODO: add column_types field to Dataset
|
// 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
|
// We return true if column_types is undefined or empty as a precaution against backend failing to return column_types
|
||||||
export const hasTemporalColumns = (
|
export const hasTemporalColumns = (dataset: Dataset) => {
|
||||||
dataset: Dataset & { column_types: GenericDataType[] },
|
|
||||||
) => {
|
|
||||||
const columnTypes = ensureIsArray(dataset?.column_types);
|
const columnTypes = ensureIsArray(dataset?.column_types);
|
||||||
return (
|
return (
|
||||||
columnTypes.length === 0 || columnTypes.includes(GenericDataType.TEMPORAL)
|
columnTypes.length === 0 || columnTypes.includes(GenericDataType.TEMPORAL)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* eslint-disable import/prefer-default-export */
|
/* eslint-disable import/prefer-default-export */
|
||||||
import { DatasourceType } from '@superset-ui/core';
|
import { DatasourceType } from '@superset-ui/core';
|
||||||
import { Datasource } from 'src/dashboard/types';
|
import { Dataset } from '@superset-ui/chart-controls';
|
||||||
/**
|
/**
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
* or more contributor license agreements. See the NOTICE file
|
* or more contributor license agreements. See the NOTICE file
|
||||||
@ -19,7 +19,7 @@ import { Datasource } from 'src/dashboard/types';
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
export const PLACEHOLDER_DATASOURCE: Datasource = {
|
export const PLACEHOLDER_DATASOURCE: Dataset = {
|
||||||
id: 0,
|
id: 0,
|
||||||
type: DatasourceType.Table,
|
type: DatasourceType.Table,
|
||||||
uid: '_placeholder_',
|
uid: '_placeholder_',
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
addSliceToDashboard,
|
addSliceToDashboard,
|
||||||
removeSliceFromDashboard,
|
removeSliceFromDashboard,
|
||||||
} from 'src/dashboard/actions/dashboardState';
|
} from 'src/dashboard/actions/dashboardState';
|
||||||
import { setDatasources } from 'src/dashboard/actions/datasources';
|
import { setDatasources } from 'src/datasource/actions';
|
||||||
|
|
||||||
import { triggerQuery } from 'src/components/Chart/chartAction';
|
import { triggerQuery } from 'src/components/Chart/chartAction';
|
||||||
import { logEvent } from 'src/logger/actions';
|
import { logEvent } from 'src/logger/actions';
|
||||||
|
@ -36,7 +36,7 @@ import {
|
|||||||
useDashboardDatasets,
|
useDashboardDatasets,
|
||||||
} from 'src/hooks/apiResources';
|
} from 'src/hooks/apiResources';
|
||||||
import { hydrateDashboard } from 'src/dashboard/actions/hydrate';
|
import { hydrateDashboard } from 'src/dashboard/actions/hydrate';
|
||||||
import { setDatasources } from 'src/dashboard/actions/datasources';
|
import { setDatasources } from 'src/datasource/actions';
|
||||||
import injectCustomCss from 'src/dashboard/util/injectCustomCss';
|
import injectCustomCss from 'src/dashboard/util/injectCustomCss';
|
||||||
import setupPlugins from 'src/setup/setupPlugins';
|
import setupPlugins from 'src/setup/setupPlugins';
|
||||||
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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 || {};
|
|
||||||
}
|
|
@ -20,7 +20,6 @@ import {
|
|||||||
ChartProps,
|
ChartProps,
|
||||||
DataMaskStateWithId,
|
DataMaskStateWithId,
|
||||||
ExtraFormData,
|
ExtraFormData,
|
||||||
GenericDataType,
|
|
||||||
JsonObject,
|
JsonObject,
|
||||||
NativeFiltersState,
|
NativeFiltersState,
|
||||||
} from '@superset-ui/core';
|
} from '@superset-ui/core';
|
||||||
@ -84,13 +83,8 @@ export type DashboardInfo = {
|
|||||||
|
|
||||||
export type ChartsState = { [key: string]: Chart };
|
export type ChartsState = { [key: string]: Chart };
|
||||||
|
|
||||||
export type Datasource = Dataset & {
|
|
||||||
uid: string;
|
|
||||||
column_types: GenericDataType[];
|
|
||||||
table_name: string;
|
|
||||||
};
|
|
||||||
export type DatasourcesState = {
|
export type DatasourcesState = {
|
||||||
[key: string]: Datasource;
|
[key: string]: Dataset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Root state of redux */
|
/** Root state of redux */
|
||||||
|
@ -18,39 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { SupersetClient } from '@superset-ui/core';
|
import { SupersetClient } from '@superset-ui/core';
|
||||||
import { Datasource, RootState } from 'src/dashboard/types';
|
import { Dataset } from '@superset-ui/chart-controls';
|
||||||
|
import { RootState } from 'src/dashboard/types';
|
||||||
// update datasources index for Dashboard
|
import { setDatasource } from 'src/datasource/actions';
|
||||||
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) {
|
export function fetchDatasourceMetadata(key: string) {
|
||||||
return (dispatch: Dispatch, getState: () => RootState) => {
|
return (dispatch: Dispatch, getState: () => RootState) => {
|
||||||
@ -58,11 +28,11 @@ export function fetchDatasourceMetadata(key: string) {
|
|||||||
const datasource = datasources[key];
|
const datasource = datasources[key];
|
||||||
|
|
||||||
if (datasource) {
|
if (datasource) {
|
||||||
return dispatch(setDatasource(datasource, key));
|
return dispatch(setDatasource(datasource));
|
||||||
}
|
}
|
||||||
|
|
||||||
return SupersetClient.get({
|
return SupersetClient.get({
|
||||||
endpoint: `/superset/fetch_datasource_metadata?datasourceKey=${key}`,
|
endpoint: `/superset/fetch_datasource_metadata?datasourceKey=${key}`,
|
||||||
}).then(({ json }) => dispatch(setDatasource(json as Datasource, key)));
|
}).then(({ json }) => dispatch(setDatasource(json as Dataset)));
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -16,34 +16,39 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Dispatch } from 'redux';
|
|
||||||
import { Dataset } from '@superset-ui/chart-controls';
|
import { Dataset } from '@superset-ui/chart-controls';
|
||||||
import { updateFormDataByDatasource } from './exploreActions';
|
|
||||||
import { ExplorePageState } from '../types';
|
|
||||||
|
|
||||||
export const SET_DATASOURCE = 'SET_DATASOURCE';
|
export enum DatasourcesActionType {
|
||||||
export interface SetDatasource {
|
INIT_DATASOURCES = 'INIT_DATASOURCES',
|
||||||
type: string;
|
SET_DATASOURCE = 'SET_DATASOURCE',
|
||||||
datasource: Dataset;
|
SET_DATASOURCES = 'SET_DATASOURCES',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
export function setDatasource(datasource: Dataset) {
|
||||||
return { type: SET_DATASOURCE, datasource };
|
return { type: DatasourcesActionType.SET_DATASOURCE, datasource };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function changeDatasource(newDatasource: Dataset) {
|
export function setDatasources(datasources: Dataset[] | null) {
|
||||||
return function (dispatch: Dispatch, getState: () => ExplorePageState) {
|
return {
|
||||||
const {
|
type: DatasourcesActionType.SET_DATASOURCES,
|
||||||
explore: { datasource: prevDatasource },
|
datasources,
|
||||||
} = getState();
|
|
||||||
dispatch(setDatasource(newDatasource));
|
|
||||||
dispatch(updateFormDataByDatasource(prevDatasource, newDatasource));
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const datasourcesActions = {
|
|
||||||
setDatasource,
|
|
||||||
changeDatasource,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type AnyDatasourcesAction = SetDatasource;
|
|
@ -16,27 +16,32 @@
|
|||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { Dataset } from '@superset-ui/chart-controls';
|
import { keyBy } from 'lodash';
|
||||||
import { getDatasourceUid } from 'src/utils/getDatasourceUid';
|
import { getDatasourceUid } from 'src/utils/getDatasourceUid';
|
||||||
import {
|
import {
|
||||||
AnyDatasourcesAction,
|
DatasourcesAction,
|
||||||
SET_DATASOURCE,
|
DatasourcesActionType,
|
||||||
} from '../actions/datasourcesActions';
|
} from 'src/datasource/actions';
|
||||||
import { HYDRATE_EXPLORE, HydrateExplore } from '../actions/hydrateExplore';
|
import { Dataset } from '@superset-ui/chart-controls';
|
||||||
|
|
||||||
export default function datasourcesReducer(
|
export default function datasourcesReducer(
|
||||||
// TODO: change type to include other datasource types
|
datasources: { [key: string]: Dataset } | undefined,
|
||||||
datasources: { [key: string]: Dataset },
|
action: DatasourcesAction,
|
||||||
action: AnyDatasourcesAction | HydrateExplore,
|
|
||||||
) {
|
) {
|
||||||
if (action.type === SET_DATASOURCE) {
|
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) {
|
||||||
return {
|
return {
|
||||||
...datasources,
|
...datasources,
|
||||||
[getDatasourceUid(action.datasource)]: action.datasource,
|
[getDatasourceUid(action.datasource)]: action.datasource,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (action.type === HYDRATE_EXPLORE) {
|
|
||||||
return { ...(action as HydrateExplore).data.datasources };
|
|
||||||
}
|
|
||||||
return datasources || {};
|
return datasources || {};
|
||||||
}
|
}
|
@ -1,85 +0,0 @@
|
|||||||
/**
|
|
||||||
* 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),
|
|
||||||
);
|
|
||||||
});
|
|
@ -25,6 +25,8 @@ import {
|
|||||||
toastActions,
|
toastActions,
|
||||||
} from 'src/components/MessageToasts/actions';
|
} from 'src/components/MessageToasts/actions';
|
||||||
import { Slice } from 'src/types/Chart';
|
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';
|
const FAVESTAR_BASE_URL = '/superset/favstar/slice';
|
||||||
|
|
||||||
@ -140,6 +142,16 @@ export function setForceQuery(force: boolean) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 = {
|
export const exploreActions = {
|
||||||
...toastActions,
|
...toastActions,
|
||||||
fetchDatasourcesStarted,
|
fetchDatasourcesStarted,
|
||||||
@ -153,6 +165,7 @@ export const exploreActions = {
|
|||||||
createNewSlice,
|
createNewSlice,
|
||||||
sliceUpdated,
|
sliceUpdated,
|
||||||
setForceQuery,
|
setForceQuery,
|
||||||
|
changeDatasource,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ExploreActions = typeof exploreActions;
|
export type ExploreActions = typeof exploreActions;
|
||||||
|
@ -64,9 +64,6 @@ test('creates hydrate action from initial data', () => {
|
|||||||
lastRendered: 0,
|
lastRendered: 0,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
datasources: {
|
|
||||||
'8__table': exploreInitialData.dataset,
|
|
||||||
},
|
|
||||||
saveModal: {
|
saveModal: {
|
||||||
dashboards: [],
|
dashboards: [],
|
||||||
saveModalAlert: null,
|
saveModalAlert: null,
|
||||||
|
@ -35,6 +35,7 @@ import { getDatasourceUid } from 'src/utils/getDatasourceUid';
|
|||||||
import { getUrlParam } from 'src/utils/urlUtils';
|
import { getUrlParam } from 'src/utils/urlUtils';
|
||||||
import { URL_PARAMS } from 'src/constants';
|
import { URL_PARAMS } from 'src/constants';
|
||||||
import { findPermission } from 'src/utils/findPermission';
|
import { findPermission } from 'src/utils/findPermission';
|
||||||
|
import { initDatasources } from 'src/datasource/actions';
|
||||||
|
|
||||||
export const HYDRATE_EXPLORE = 'HYDRATE_EXPLORE';
|
export const HYDRATE_EXPLORE = 'HYDRATE_EXPLORE';
|
||||||
export const hydrateExplore =
|
export const hydrateExplore =
|
||||||
@ -121,6 +122,13 @@ export const hydrateExplore =
|
|||||||
lastRendered: 0,
|
lastRendered: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dispatch(
|
||||||
|
initDatasources({
|
||||||
|
...datasources,
|
||||||
|
[getDatasourceUid(initialDatasource)]: initialDatasource,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
return dispatch({
|
return dispatch({
|
||||||
type: HYDRATE_EXPLORE,
|
type: HYDRATE_EXPLORE,
|
||||||
data: {
|
data: {
|
||||||
@ -128,10 +136,6 @@ export const hydrateExplore =
|
|||||||
...charts,
|
...charts,
|
||||||
[chartKey]: chart,
|
[chartKey]: chart,
|
||||||
},
|
},
|
||||||
datasources: {
|
|
||||||
...datasources,
|
|
||||||
[getDatasourceUid(initialDatasource)]: initialDatasource,
|
|
||||||
},
|
|
||||||
saveModal: {
|
saveModal: {
|
||||||
dashboards: [],
|
dashboards: [],
|
||||||
saveModalAlert: null,
|
saveModalAlert: null,
|
||||||
|
@ -46,11 +46,10 @@ import {
|
|||||||
import { getUrlParam } from 'src/utils/urlUtils';
|
import { getUrlParam } from 'src/utils/urlUtils';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import * as chartActions from 'src/components/Chart/chartAction';
|
import * as chartActions from 'src/components/Chart/chartAction';
|
||||||
import { fetchDatasourceMetadata } from 'src/dashboard/actions/datasources';
|
import { fetchDatasourceMetadata } from 'src/dashboard/util/fetchDatasourceMetadata';
|
||||||
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
import { chartPropShape } from 'src/dashboard/util/propShapes';
|
||||||
import { mergeExtraFormData } from 'src/dashboard/components/nativeFilters/utils';
|
import { mergeExtraFormData } from 'src/dashboard/components/nativeFilters/utils';
|
||||||
import { postFormData, putFormData } from 'src/explore/exploreUtils/formData';
|
import { postFormData, putFormData } from 'src/explore/exploreUtils/formData';
|
||||||
import { datasourcesActions } from 'src/explore/actions/datasourcesActions';
|
|
||||||
import { mountExploreUrl } from 'src/explore/exploreUtils';
|
import { mountExploreUrl } from 'src/explore/exploreUtils';
|
||||||
import { getFormDataFromControls } from 'src/explore/controlUtils';
|
import { getFormDataFromControls } from 'src/explore/controlUtils';
|
||||||
import * as exploreActions from 'src/explore/actions/exploreActions';
|
import * as exploreActions from 'src/explore/actions/exploreActions';
|
||||||
@ -758,7 +757,6 @@ function mapStateToProps(state) {
|
|||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
const actions = {
|
const actions = {
|
||||||
...exploreActions,
|
...exploreActions,
|
||||||
...datasourcesActions,
|
|
||||||
...saveModalActions,
|
...saveModalActions,
|
||||||
...chartActions,
|
...chartActions,
|
||||||
...logActions,
|
...logActions,
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Dashboard, Datasource, EmbeddedDashboard } from 'src/dashboard/types';
|
import { Dashboard, EmbeddedDashboard } from 'src/dashboard/types';
|
||||||
|
import { Dataset } from '@superset-ui/chart-controls';
|
||||||
import { Chart } from 'src/types/Chart';
|
import { Chart } from 'src/types/Chart';
|
||||||
import { useApiV1Resource, useTransformedResource } from './apiResources';
|
import { useApiV1Resource, useTransformedResource } from './apiResources';
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ export const useDashboardCharts = (idOrSlug: string | number) =>
|
|||||||
// important: this endpoint only returns the fields in the dataset
|
// important: this endpoint only returns the fields in the dataset
|
||||||
// that are necessary for rendering the given dashboard
|
// that are necessary for rendering the given dashboard
|
||||||
export const useDashboardDatasets = (idOrSlug: string | number) =>
|
export const useDashboardDatasets = (idOrSlug: string | number) =>
|
||||||
useApiV1Resource<Datasource[]>(`/api/v1/dashboard/${idOrSlug}/datasets`);
|
useApiV1Resource<Dataset[]>(`/api/v1/dashboard/${idOrSlug}/datasets`);
|
||||||
|
|
||||||
export const useEmbeddedDashboard = (idOrSlug: string | number) =>
|
export const useEmbeddedDashboard = (idOrSlug: string | number) =>
|
||||||
useApiV1Resource<EmbeddedDashboard>(`/api/v1/dashboard/${idOrSlug}/embedded`);
|
useApiV1Resource<EmbeddedDashboard>(`/api/v1/dashboard/${idOrSlug}/embedded`);
|
||||||
|
@ -27,26 +27,17 @@ import dashboardInfo from 'src/dashboard/reducers/dashboardInfo';
|
|||||||
import dashboardState from 'src/dashboard/reducers/dashboardState';
|
import dashboardState from 'src/dashboard/reducers/dashboardState';
|
||||||
import dashboardFilters from 'src/dashboard/reducers/dashboardFilters';
|
import dashboardFilters from 'src/dashboard/reducers/dashboardFilters';
|
||||||
import nativeFilters from 'src/dashboard/reducers/nativeFilters';
|
import nativeFilters from 'src/dashboard/reducers/nativeFilters';
|
||||||
import dashboardDatasources from 'src/dashboard/reducers/datasources';
|
import datasources from 'src/datasource/reducer';
|
||||||
import sliceEntities from 'src/dashboard/reducers/sliceEntities';
|
import sliceEntities from 'src/dashboard/reducers/sliceEntities';
|
||||||
import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout';
|
import dashboardLayout from 'src/dashboard/reducers/undoableDashboardLayout';
|
||||||
import logger from 'src/middleware/loggerMiddleware';
|
import logger from 'src/middleware/loggerMiddleware';
|
||||||
import saveModal from 'src/explore/reducers/saveModalReducer';
|
import saveModal from 'src/explore/reducers/saveModalReducer';
|
||||||
import explore from 'src/explore/reducers/exploreReducer';
|
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 shortid from 'shortid';
|
||||||
import {
|
import {
|
||||||
BootstrapUser,
|
BootstrapUser,
|
||||||
UserWithPermissionsAndRoles,
|
UserWithPermissionsAndRoles,
|
||||||
} from 'src/types/bootstrapTypes';
|
} 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".
|
// 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.
|
// This may change later, as the client application takes on more responsibilities.
|
||||||
@ -75,26 +66,6 @@ const userReducer = (
|
|||||||
return user;
|
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
|
// exported for tests
|
||||||
export const rootReducer = combineReducers({
|
export const rootReducer = combineReducers({
|
||||||
messageToasts: messageToastReducer,
|
messageToasts: messageToastReducer,
|
||||||
@ -102,7 +73,7 @@ export const rootReducer = combineReducers({
|
|||||||
user: userReducer,
|
user: userReducer,
|
||||||
impressionId: noopReducer(shortid.generate()),
|
impressionId: noopReducer(shortid.generate()),
|
||||||
charts,
|
charts,
|
||||||
datasources: CombinedDatasourceReducers,
|
datasources,
|
||||||
dashboardInfo,
|
dashboardInfo,
|
||||||
dashboardFilters,
|
dashboardFilters,
|
||||||
dataMask,
|
dataMask,
|
||||||
|
Loading…
Reference in New Issue
Block a user