Skip to content

Commit

Permalink
feat: Cross filters scoping (#24020)
Browse files Browse the repository at this point in the history
  • Loading branch information
kgabryje authored May 16, 2023
1 parent fa0bf38 commit 4f3fbd3
Show file tree
Hide file tree
Showing 36 changed files with 2,200 additions and 519 deletions.
37 changes: 19 additions & 18 deletions superset-frontend/src/components/DropdownSelectableIcon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,25 @@ const StyleSubmenuItem = styled.div`
export default (props: DropDownSelectableProps) => {
const theme = useTheme();
const { icon, info, menuItems, selectedKeys, onSelect } = props;
const menuItem = (
label: string | React.ReactNode,
key: string,
divider?: boolean,
) => (
<StyleMenuItem key={key} divider={divider}>
<StyleSubmenuItem>
<span>{label}</span>
{selectedKeys?.includes(key) && (
<Icons.Check
iconColor={theme.colors.primary.base}
className="tick-menu-item"
iconSize="xl"
/>
)}
</StyleSubmenuItem>
</StyleMenuItem>
const menuItem = useMemo(
() => (label: string | React.ReactNode, key: string, divider?: boolean) =>
(
<StyleMenuItem key={key} divider={divider}>
<StyleSubmenuItem>
<span>{label}</span>
{selectedKeys?.includes(key) && (
<Icons.Check
iconColor={theme.colors.primary.base}
className="tick-menu-item"
iconSize="xl"
/>
)}
</StyleSubmenuItem>
</StyleMenuItem>
),
[selectedKeys, theme.colors.primary.base],
);

const overlayMenu = useMemo(
() => (
<StyledMenu selectedKeys={selectedKeys} onSelect={onSelect} selectable>
Expand All @@ -141,7 +142,7 @@ export default (props: DropDownSelectableProps) => {
)}
</StyledMenu>
),
[info, menuItems],
[selectedKeys, onSelect, info, menuItems, menuItem],
);

return (
Expand Down
15 changes: 11 additions & 4 deletions superset-frontend/src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
import React, { useMemo, useRef, useState } from 'react';
import React, {
CSSProperties,
ReactNode,
useMemo,
useRef,
useState,
} from 'react';
import { isNil } from 'lodash';
import { ModalFuncProps } from 'antd/lib/modal';
import { styled, t } from '@superset-ui/core';
Expand All @@ -33,7 +39,7 @@ import Draggable, {

export interface ModalProps {
className?: string;
children: React.ReactNode;
children: ReactNode;
disablePrimaryButton?: boolean;
primaryButtonLoading?: boolean;
onHide: () => void;
Expand All @@ -42,13 +48,13 @@ export interface ModalProps {
primaryButtonType?: 'primary' | 'danger';
show: boolean;
name?: string;
title: React.ReactNode;
title: ReactNode;
width?: string;
maxWidth?: string;
responsive?: boolean;
hideFooter?: boolean;
centered?: boolean;
footer?: React.ReactNode;
footer?: ReactNode;
wrapProps?: object;
height?: string;
closable?: boolean;
Expand All @@ -59,6 +65,7 @@ export interface ModalProps {
destroyOnClose?: boolean;
maskClosable?: boolean;
zIndex?: number;
bodyStyle?: CSSProperties;
}

interface StyledModalProps {
Expand Down
64 changes: 32 additions & 32 deletions superset-frontend/src/dashboard/actions/dashboardInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,17 @@
* under the License.
*/
import { Dispatch } from 'redux';
import { makeApi, CategoricalColorNamespace } from '@superset-ui/core';
import { makeApi, CategoricalColorNamespace, t } from '@superset-ui/core';
import { isString } from 'lodash';
import { getErrorText } from 'src/utils/getClientErrorObject';
import { addDangerToast } from 'src/components/MessageToasts/actions';
import {
ChartConfiguration,
DashboardInfo,
FilterBarOrientation,
GlobalChartCrossFilterConfig,
RootState,
} from 'src/dashboard/types';
import { ChartConfiguration } from 'src/dashboard/reducers/types';
import { onSave } from './dashboardState';

export const DASHBOARD_INFO_UPDATED = 'DASHBOARD_INFO_UPDATED';
Expand Down Expand Up @@ -66,27 +67,23 @@ export function dashboardInfoChanged(newInfo: { metadata: any }) {

return { type: DASHBOARD_INFO_UPDATED, newInfo };
}
export const SET_CHART_CONFIG_BEGIN = 'SET_CHART_CONFIG_BEGIN';
export interface SetChartConfigBegin {
type: typeof SET_CHART_CONFIG_BEGIN;
chartConfiguration: ChartConfiguration;
}
export const SET_CHART_CONFIG_COMPLETE = 'SET_CHART_CONFIG_COMPLETE';
export interface SetChartConfigComplete {
type: typeof SET_CHART_CONFIG_COMPLETE;
chartConfiguration: ChartConfiguration;
}
export const SET_CHART_CONFIG_FAIL = 'SET_CHART_CONFIG_FAIL';
export interface SetChartConfigFail {
type: typeof SET_CHART_CONFIG_FAIL;
chartConfiguration: ChartConfiguration;
}
export const setChartConfiguration =
(chartConfiguration: ChartConfiguration) =>
async (dispatch: Dispatch, getState: () => any) => {
export const SAVE_CHART_CONFIG_BEGIN = 'SAVE_CHART_CONFIG_BEGIN';
export const SAVE_CHART_CONFIG_COMPLETE = 'SAVE_CHART_CONFIG_COMPLETE';
export const SAVE_CHART_CONFIG_FAIL = 'SAVE_CHART_CONFIG_FAIL';

export const saveChartConfiguration =
({
chartConfiguration,
globalChartConfiguration,
}: {
chartConfiguration?: ChartConfiguration;
globalChartConfiguration?: GlobalChartCrossFilterConfig;
}) =>
async (dispatch: Dispatch, getState: () => RootState) => {
dispatch({
type: SET_CHART_CONFIG_BEGIN,
type: SAVE_CHART_CONFIG_BEGIN,
chartConfiguration,
globalChartConfiguration,
});
const { id, metadata } = getState().dashboardInfo;

Expand All @@ -103,7 +100,10 @@ export const setChartConfiguration =
const response = await updateDashboard({
json_metadata: JSON.stringify({
...metadata,
chart_configuration: chartConfiguration,
chart_configuration:
chartConfiguration ?? metadata.chart_configuration,
global_chart_configuration:
globalChartConfiguration ?? metadata.global_chart_configuration,
}),
});
dispatch(
Expand All @@ -112,30 +112,30 @@ export const setChartConfiguration =
}),
);
dispatch({
type: SET_CHART_CONFIG_COMPLETE,
type: SAVE_CHART_CONFIG_COMPLETE,
chartConfiguration,
globalChartConfiguration,
});
} catch (err) {
dispatch({ type: SET_CHART_CONFIG_FAIL, chartConfiguration });
dispatch({
type: SAVE_CHART_CONFIG_FAIL,
chartConfiguration,
globalChartConfiguration,
});
dispatch(addDangerToast(t('Failed to save cross-filter scoping')));
}
};

export const SET_FILTER_BAR_ORIENTATION = 'SET_FILTER_BAR_ORIENTATION';
export interface SetFilterBarOrientation {
type: typeof SET_FILTER_BAR_ORIENTATION;
filterBarOrientation: FilterBarOrientation;
}

export function setFilterBarOrientation(
filterBarOrientation: FilterBarOrientation,
) {
return { type: SET_FILTER_BAR_ORIENTATION, filterBarOrientation };
}

export const SET_CROSS_FILTERS_ENABLED = 'SET_CROSS_FILTERS_ENABLED';
export interface SetCrossFiltersEnabled {
type: typeof SET_CROSS_FILTERS_ENABLED;
crossFiltersEnabled: boolean;
}

export function setCrossFiltersEnabled(crossFiltersEnabled: boolean) {
return { type: SET_CROSS_FILTERS_ENABLED, crossFiltersEnabled };
}
Expand Down
36 changes: 17 additions & 19 deletions superset-frontend/src/dashboard/actions/dashboardState.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ import { logEvent } from 'src/logger/actions';
import { LOG_ACTIONS_CONFIRM_OVERWRITE_DASHBOARD_METADATA } from 'src/logger/LogUtils';
import { UPDATE_COMPONENTS_PARENTS_LIST } from './dashboardLayout';
import {
setChartConfiguration,
saveChartConfiguration,
dashboardInfoChanged,
SET_CHART_CONFIG_COMPLETE,
SAVE_CHART_CONFIG_COMPLETE,
} from './dashboardInfo';
import { fetchDatasourceMetadata } from './datasources';
import {
Expand Down Expand Up @@ -89,7 +89,6 @@ export function toggleFaveStar(isStarred) {
return { type: TOGGLE_FAVE_STAR, isStarred };
}

export const FETCH_FAVE_STAR = 'FETCH_FAVE_STAR';
export function fetchFaveStar(id) {
return function fetchFaveStarThunk(dispatch) {
return SupersetClient.get({
Expand All @@ -110,7 +109,6 @@ export function fetchFaveStar(id) {
};
}

export const SAVE_FAVE_STAR = 'SAVE_FAVE_STAR';
export function saveFaveStar(id, isStarred) {
return function saveFaveStarThunk(dispatch) {
const endpoint = `/api/v1/dashboard/${id}/favorites/`;
Expand Down Expand Up @@ -287,13 +285,11 @@ export function saveDashboardRequest(data, id, saveType) {
const {
dashboardLayout,
charts,
dashboardInfo: {
metadata: { chart_configuration = {} },
},
dashboardInfo: { metadata },
} = getState();
return getCrossFiltersConfiguration(
dashboardLayout.present,
chart_configuration,
metadata,
charts,
);
};
Expand All @@ -304,8 +300,14 @@ export function saveDashboardRequest(data, id, saveType) {
dispatch(saveDashboardRequestSuccess(lastModifiedTime));
}
if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
const chartConfiguration = handleChartConfiguration();
dispatch(setChartConfiguration(chartConfiguration));
const { chartConfiguration, globalChartConfiguration } =
handleChartConfiguration();
dispatch(
saveChartConfiguration({
chartConfiguration,
globalChartConfiguration,
}),
);
}
dispatch(saveDashboardFinished());
dispatch(addSuccessToast(t('This dashboard was saved successfully.')));
Expand All @@ -325,7 +327,7 @@ export function saveDashboardRequest(data, id, saveType) {
);
if (metadata.chart_configuration) {
dispatch({
type: SET_CHART_CONFIG_COMPLETE,
type: SAVE_CHART_CONFIG_COMPLETE,
chartConfiguration: metadata.chart_configuration,
});
}
Expand Down Expand Up @@ -373,8 +375,10 @@ export function saveDashboardRequest(data, id, saveType) {
[SAVE_TYPE_OVERWRITE, SAVE_TYPE_OVERWRITE_CONFIRMED].includes(saveType)
) {
let chartConfiguration = {};
let globalChartConfiguration = {};
if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
chartConfiguration = handleChartConfiguration();
({ chartConfiguration, globalChartConfiguration } =
handleChartConfiguration());
}
const updatedDashboard =
saveType === SAVE_TYPE_OVERWRITE_CONFIRMED
Expand All @@ -392,6 +396,7 @@ export function saveDashboardRequest(data, id, saveType) {
default_filters: safeStringify(serializedFilters),
filter_scopes: serializedFilterScopes,
chart_configuration: chartConfiguration,
global_chart_configuration: globalChartConfiguration,
}),
};

Expand Down Expand Up @@ -601,13 +606,6 @@ export function setColorScheme(colorScheme) {
return { type: SET_COLOR_SCHEME, colorScheme };
}

export function setColorSchemeAndUnsavedChanges(colorScheme) {
return dispatch => {
dispatch(setColorScheme(colorScheme));
dispatch(setUnsavedChanges(true));
};
}

export const SET_DIRECT_PATH = 'SET_DIRECT_PATH';
export function setDirectPathToChild(path) {
return { type: SET_DIRECT_PATH, path };
Expand Down
13 changes: 8 additions & 5 deletions superset-frontend/src/dashboard/actions/hydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,11 +309,14 @@ export const hydrateDashboard =
});

if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
metadata.chart_configuration = getCrossFiltersConfiguration(
dashboardLayout.present,
metadata.chart_configuration,
chartQueries,
);
const { chartConfiguration, globalChartConfiguration } =
getCrossFiltersConfiguration(
dashboardLayout.present,
metadata,
chartQueries,
);
metadata.chart_configuration = chartConfiguration;
metadata.global_chart_configuration = globalChartConfiguration;
}

const { roles } = user;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import pick from 'lodash/pick';
import Tabs from 'src/components/Tabs';
import DashboardGrid from 'src/dashboard/containers/DashboardGrid';
import {
ChartsState,
DashboardInfo,
DashboardLayout,
LayoutItem,
Expand Down Expand Up @@ -86,7 +85,9 @@ const DashboardContainer: FC<DashboardContainerProps> = ({ topLevelTabs }) => {
const directPathToChild = useSelector<RootState, string[]>(
state => state.dashboardState.directPathToChild,
);
const charts = useSelector<RootState, ChartsState>(state => state.charts);
const chartIds = useSelector<RootState, number[]>(state =>
Object.values(state.charts).map(chart => chart.id),
);

const tabIndex = useMemo(() => {
const nextTabIndex = findTabIndexByComponentId({
Expand Down Expand Up @@ -116,7 +117,7 @@ const DashboardContainer: FC<DashboardContainerProps> = ({ topLevelTabs }) => {
}
const chartsInScope: number[] = getChartIdsInFilterScope(
filterScope.scope,
charts,
chartIds,
dashboardLayout,
);
const tabsInScope = findTabsWithChartsInScope(
Expand Down Expand Up @@ -207,7 +208,7 @@ const DashboardContainer: FC<DashboardContainerProps> = ({ topLevelTabs }) => {
}
}
}
}, [charts]);
}, [chartIds]);

useComponentDidUpdate(verifyUpdateColorScheme);

Expand Down
Loading

0 comments on commit 4f3fbd3

Please sign in to comment.