Skip to content

Commit

Permalink
fix: Further drill by different groupby fields
Browse files Browse the repository at this point in the history
  • Loading branch information
kgabryje committed Apr 20, 2023
1 parent f80e738 commit 75a15ba
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,7 @@ const ChartContextMenu = (
}
menuItems.push(
<DrillByMenuItems
filters={filters?.drillBy?.filters}
groupbyFieldName={filters?.drillBy?.groupbyFieldName}
adhocFilterFieldName={filters?.drillBy?.adhocFilterFieldName}
drillByConfig={filters?.drillBy}
onSelection={onSelection}
formData={formData}
contextMenuY={clientY}
Expand Down
30 changes: 13 additions & 17 deletions superset-frontend/src/components/Chart/DrillBy/DrillByMenuItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ import { Menu } from 'src/components/Menu';
import {
BaseFormData,
Behavior,
BinaryQueryObjectFilterClause,
Column,
ContextMenuFilters,
css,
ensureIsArray,
getChartMetadataRegistry,
Expand All @@ -55,22 +55,18 @@ const SHOW_COLUMNS_SEARCH_THRESHOLD = 10;
const SEARCH_INPUT_HEIGHT = 48;

export interface DrillByMenuItemsProps {
filters?: BinaryQueryObjectFilterClause[];
drillByConfig?: ContextMenuFilters['drillBy'];
formData: BaseFormData & { [key: string]: any };
contextMenuY?: number;
submenuIndex?: number;
groupbyFieldName?: string;
adhocFilterFieldName?: string;
onSelection?: (...args: any) => void;
onClick?: (event: MouseEvent) => void;
openNewModal?: boolean;
excludedColumns?: Column[];
}

export const DrillByMenuItems = ({
filters,
groupbyFieldName,
adhocFilterFieldName,
drillByConfig,
formData,
contextMenuY = 0,
submenuIndex = 0,
Expand All @@ -90,13 +86,13 @@ export const DrillByMenuItems = ({
const handleSelection = useCallback(
(event, column) => {
onClick(event);
onSelection(column, filters);
onSelection(column, drillByConfig);
setCurrentColumn(column);
if (openNewModal) {
setShowModal(true);
}
},
[filters, onClick, onSelection, openNewModal],
[drillByConfig, onClick, onSelection, openNewModal],
);
const closeModal = useCallback(() => {
setShowModal(false);
Expand All @@ -108,7 +104,9 @@ export const DrillByMenuItems = ({
setSearchInput('');
}, [columns.length]);

const hasDrillBy = ensureIsArray(filters).length && groupbyFieldName;
const hasDrillBy =
ensureIsArray(drillByConfig?.filters).length &&
drillByConfig?.groupbyFieldName;

const handlesDimensionContextMenu = useMemo(
() =>
Expand All @@ -131,9 +129,9 @@ export const DrillByMenuItems = ({
.filter(column => column.groupby)
.filter(
column =>
!ensureIsArray(formData[groupbyFieldName]).includes(
column.column_name,
) &&
!ensureIsArray(
formData[drillByConfig.groupbyFieldName ?? ''],
).includes(column.column_name) &&
column.column_name !== formData.x_axis &&
ensureIsArray(excludedColumns)?.every(
excludedCol =>
Expand All @@ -151,7 +149,7 @@ export const DrillByMenuItems = ({
addDangerToast,
excludedColumns,
formData,
groupbyFieldName,
drillByConfig?.groupbyFieldName,
handlesDimensionContextMenu,
hasDrillBy,
]);
Expand Down Expand Up @@ -269,10 +267,8 @@ export const DrillByMenuItems = ({
{showModal && (
<DrillByModal
column={currentColumn}
filters={filters}
drillByConfig={drillByConfig}
formData={formData}
groupbyFieldName={groupbyFieldName}
adhocFilterFieldName={adhocFilterFieldName}
onHideModal={closeModal}
dataset={dataset!}
/>
Expand Down
152 changes: 102 additions & 50 deletions superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ import React, {
} from 'react';
import {
BaseFormData,
BinaryQueryObjectFilterClause,
Column,
QueryData,
css,
ensureIsArray,
isDefined,
t,
useTheme,
ContextMenuFilters,
} from '@superset-ui/core';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
Expand Down Expand Up @@ -61,6 +61,8 @@ import {
} from './useDrillByBreadcrumbs';

const DATA_SIZE = 15;

const DEFAULT_ADHOC_FILTER_FIELD_NAME = 'adhoc_filters';
interface ModalFooterProps {
closeModal?: () => void;
formData: BaseFormData;
Expand Down Expand Up @@ -123,26 +125,36 @@ const ModalFooter = ({ formData, closeModal }: ModalFooterProps) => {
export interface DrillByModalProps {
column?: Column;
dataset: Dataset;
filters?: BinaryQueryObjectFilterClause[];
drillByConfig: Required<ContextMenuFilters>['drillBy'];
formData: BaseFormData & { [key: string]: any };
groupbyFieldName?: string;
adhocFilterFieldName?: string;
onHideModal: () => void;
}

type DrillByConfigs = (ContextMenuFilters['drillBy'] & { column?: Column })[];

export default function DrillByModal({
column,
dataset,
filters,
drillByConfig,
formData,
groupbyFieldName = 'groupby',
adhocFilterFieldName = 'adhoc_filters',
onHideModal,
}: DrillByModalProps) {
const theme = useTheme();
const { addDangerToast } = useToasts();
const [isChartDataLoading, setIsChartDataLoading] = useState(true);

const [drillByConfigs, setDrillByConfigs] = useState<DrillByConfigs>([
{ ...drillByConfig, column },
]);

const {
column: currentColumn,
filters,
groupbyFieldName = drillByConfig.groupbyFieldName,
adhocFilterFieldName = drillByConfig.adhocFilterFieldName ||
DEFAULT_ADHOC_FILTER_FIELD_NAME,
} = drillByConfigs[drillByConfigs.length - 1] || {};

const initialGroupbyColumns = useMemo(
() =>
ensureIsArray(formData[groupbyFieldName])
Expand All @@ -160,11 +172,7 @@ export default function DrillByModal({
[formData.datasource],
);

const [currentColumn, setCurrentColumn] = useState<Column | undefined>(
column,
);
const [currentFormData, setCurrentFormData] = useState(formData);
const [currentFilters, setCurrentFilters] = useState(filters || []);
const [usedGroupbyColumns, setUsedGroupbyColumns] = useState<Column[]>(
[...initialGroupbyColumns, column].filter(isDefined),
);
Expand All @@ -174,19 +182,48 @@ export default function DrillByModal({
]);

const getNewGroupby = useCallback(
(groupbyCol: Column) =>
Array.isArray(formData[groupbyFieldName])
(groupbyCol: Column, fieldName = groupbyFieldName) =>
Array.isArray(formData[fieldName])
? [groupbyCol.column_name]
: groupbyCol.column_name,
[formData, groupbyFieldName],
);

const getFormDataChangesFromConfigs = useCallback(
(configs: DrillByConfigs) =>
configs.reduce(
(acc, config) => {
if (config?.groupbyFieldName && config.column) {
acc.formData[config.groupbyFieldName] = getNewGroupby(
config.column,
config.groupbyFieldName,
);
acc.overridenGroupbyFields.add(config.groupbyFieldName);
}
const adhocFilterFieldName =
config?.adhocFilterFieldName || DEFAULT_ADHOC_FILTER_FIELD_NAME;
acc.formData[adhocFilterFieldName] = [
...ensureIsArray(acc[adhocFilterFieldName]),
...ensureIsArray(config.filters).map(filter =>
simpleFilterToAdhoc(filter),
),
];
acc.overridenAdhocFilterFields.add(adhocFilterFieldName);

return acc;
},
{
formData: {},
overridenGroupbyFields: new Set<string>(),
overridenAdhocFilterFields: new Set<string>(),
},
),
[getNewGroupby],
);

const onBreadcrumbClick = useCallback(
(breadcrumb: DrillByBreadcrumb, index: number) => {
const newGroupbyCol =
index === 0 ? undefined : (breadcrumb.groupby as Column);
setCurrentColumn(newGroupbyCol);
setCurrentFilters(filters => filters.slice(0, index));
setDrillByConfigs(prevConfigs => prevConfigs.slice(0, index));
setBreadcrumbsData(prevBreadcrumbs => {
const newBreadcrumbs = prevBreadcrumbs.slice(0, index + 1);
delete newBreadcrumbs[newBreadcrumbs.length - 1].filters;
Expand All @@ -195,52 +232,61 @@ export default function DrillByModal({
setUsedGroupbyColumns(prevUsedGroupbyColumns =>
prevUsedGroupbyColumns.slice(0, index),
);
setCurrentFormData(prevFormData => ({
...prevFormData,
[groupbyFieldName]: newGroupbyCol
? getNewGroupby(newGroupbyCol)
: formData[groupbyFieldName],
[adhocFilterFieldName]: [
...formData[adhocFilterFieldName],
...prevFormData[adhocFilterFieldName].slice(
formData[adhocFilterFieldName].length,
formData[adhocFilterFieldName].length + index,
),
],
}));
setCurrentFormData(() => {
if (index === 0) {
return formData;
}
const { formData: overrideFormData, overridenAdhocFilterFields } =
getFormDataChangesFromConfigs(drillByConfigs.slice(0, index));

const newFormData = {
...formData,
...overrideFormData,
};
overridenAdhocFilterFields.forEach(adhocFilterField => ({
...newFormData,
[adhocFilterField]: [
...formData[adhocFilterField],
...overrideFormData[adhocFilterField],
],
}));
return newFormData;
});
},
[adhocFilterFieldName, formData, getNewGroupby, groupbyFieldName],
[drillByConfigs, formData, getFormDataChangesFromConfigs],
);

const breadcrumbs = useDrillByBreadcrumbs(breadcrumbsData, onBreadcrumbClick);

const drilledFormData = useMemo(() => {
let updatedFormData = { ...formData };
if (currentColumn) {
let updatedFormData = { ...currentFormData };
if (currentColumn && groupbyFieldName) {
updatedFormData[groupbyFieldName] = getNewGroupby(currentColumn);
}

const adhocFilters = currentFilters.map(filter =>
simpleFilterToAdhoc(filter),
);
updatedFormData = {
...updatedFormData,
[adhocFilterFieldName]: [
...ensureIsArray(formData[adhocFilterFieldName]),
...adhocFilters,
],
};
if (adhocFilterFieldName && Array.isArray(filters)) {
const adhocFilters = filters.map(filter => simpleFilterToAdhoc(filter));
updatedFormData = {
...updatedFormData,
[adhocFilterFieldName]: [
...ensureIsArray(formData[adhocFilterFieldName]),
...adhocFilters,
],
};
}

updatedFormData.slice_id = 0;
delete updatedFormData.slice_name;
delete updatedFormData.dashboards;
return updatedFormData;
}, [
formData,
currentFormData,
currentColumn,
currentFilters,
filters,
adhocFilterFieldName,
formData,
groupbyFieldName,
getNewGroupby,
adhocFilterFieldName,
]);

useEffect(() => {
Expand All @@ -255,13 +301,19 @@ export default function DrillByModal({
}, [currentColumn]);

const onSelection = useCallback(
(newColumn: Column, filters: BinaryQueryObjectFilterClause[]) => {
setCurrentColumn(newColumn);
(
newColumn: Column,
drillByConfig: Required<ContextMenuFilters>['drillBy'],
) => {
setCurrentFormData(drilledFormData);
setCurrentFilters(prevFilters => [...prevFilters, ...filters]);
setDrillByConfigs(prevConfigs => [
...prevConfigs,
{ ...drillByConfig, column: newColumn },
]);
setBreadcrumbsData(prevBreadcrumbs => {
const newBreadcrumbs = [...prevBreadcrumbs, { groupby: newColumn }];
newBreadcrumbs[newBreadcrumbs.length - 2].filters = filters;
newBreadcrumbs[newBreadcrumbs.length - 2].filters =
drillByConfig.filters;
return newBreadcrumbs;
});
},
Expand Down

0 comments on commit 75a15ba

Please sign in to comment.