feat(dashboard): Add cross filter from context menu (#23141)

This commit is contained in:
Kamil Gabryjelski
2023-02-23 17:05:41 +01:00
committed by GitHub
parent 95eb8d79d0
commit ee1952e488
26 changed files with 896 additions and 753 deletions

View File

@@ -279,6 +279,70 @@ export default function PivotTableChart(props: PivotTableProps) {
[groupbyColumnsRaw, groupbyRowsRaw, setDataMask],
);
const getCrossFilterDataMask = useCallback(
(value: { [key: string]: string }) => {
const isActiveFilterValue = (key: string, val: DataRecordValue) =>
!!selectedFilters && selectedFilters[key]?.includes(val);
if (!value) {
return undefined;
}
const [key, val] = Object.entries(value)[0];
let values = { ...selectedFilters };
if (isActiveFilterValue(key, val)) {
values = {};
} else {
values = { [key]: [val] };
}
const filterKeys = Object.keys(values);
const groupby = [...groupbyRowsRaw, ...groupbyColumnsRaw];
return {
dataMask: {
extraFormData: {
filters:
filterKeys.length === 0
? undefined
: filterKeys.map(key => {
const val = values?.[key];
const col =
groupby.find(item => {
if (isPhysicalColumn(item)) {
return item === key;
}
if (isAdhocColumn(item)) {
return item.label === key;
}
return false;
}) ?? '';
if (val === null || val === undefined)
return {
col,
op: 'IS NULL' as const,
};
return {
col,
op: 'IN' as const,
val: val as (string | number | boolean)[],
};
}),
},
filterState: {
value:
values && Object.keys(values).length
? Object.values(values)
: null,
selectedFilters:
values && Object.keys(values).length ? values : null,
},
},
isCurrentValueSelected: isActiveFilterValue(key, val),
};
},
[groupbyColumnsRaw, groupbyRowsRaw, selectedFilters],
);
const toggleFilter = useCallback(
(
e: MouseEvent,
@@ -369,18 +433,19 @@ export default function PivotTableChart(props: PivotTableProps) {
e: MouseEvent,
colKey: (string | number | boolean)[] | undefined,
rowKey: (string | number | boolean)[] | undefined,
dataPoint: { [key: string]: string },
) => {
if (onContextMenu) {
e.preventDefault();
e.stopPropagation();
const filters: BinaryQueryObjectFilterClause[] = [];
const drillToDetailFilters: BinaryQueryObjectFilterClause[] = [];
if (colKey && colKey.length > 1) {
colKey.forEach((val, i) => {
const col = cols[i];
const formatter = dateFormatters[col];
const formattedVal = formatter?.(val as number) || String(val);
if (i > 0) {
filters.push({
drillToDetailFilters.push({
col,
op: '==',
val,
@@ -395,7 +460,7 @@ export default function PivotTableChart(props: PivotTableProps) {
const col = rows[i];
const formatter = dateFormatters[col];
const formattedVal = formatter?.(val as number) || String(val);
filters.push({
drillToDetailFilters.push({
col,
op: '==',
val,
@@ -404,7 +469,10 @@ export default function PivotTableChart(props: PivotTableProps) {
});
});
}
onContextMenu(e.clientX, e.clientY, filters);
onContextMenu(e.clientX, e.clientY, {
drillToDetail: drillToDetailFilters,
crossFilter: getCrossFilterDataMask(dataPoint),
});
}
},
[cols, dateFormatters, onContextMenu, rows, timeGrainSqla],

View File

@@ -393,6 +393,7 @@ export class TableRenderer extends React.Component {
// Iterate through columns. Jump over duplicate values.
let i = 0;
while (i < visibleColKeys.length) {
let handleContextMenu;
const colKey = visibleColKeys[i];
const colSpan = attrIdx < colKey.length ? colAttrSpans[i][attrIdx] : 1;
let colLabelClass = 'pvtColLabel';
@@ -402,6 +403,10 @@ export class TableRenderer extends React.Component {
!omittedHighlightHeaderGroups.includes(colAttrs[attrIdx])
) {
colLabelClass += ' hoverable';
handleContextMenu = e =>
this.props.onContextMenu(e, colKey, undefined, {
[attrName]: colKey[attrIdx],
});
}
if (
highlightedHeaderCells &&
@@ -434,6 +439,7 @@ export class TableRenderer extends React.Component {
attrIdx,
this.props.tableOptions.clickColumnHeaderCallback,
)}
onContextMenu={handleContextMenu}
>
{displayHeaderCell(
needToggle,
@@ -590,12 +596,17 @@ export class TableRenderer extends React.Component {
const colIncrSpan = colAttrs.length !== 0 ? 1 : 0;
const attrValueCells = rowKey.map((r, i) => {
let handleContextMenu;
let valueCellClassName = 'pvtRowLabel';
if (
highlightHeaderCellsOnHover &&
!omittedHighlightHeaderGroups.includes(rowAttrs[i])
) {
valueCellClassName += ' hoverable';
handleContextMenu = e =>
this.props.onContextMenu(e, undefined, rowKey, {
[rowAttrs[i]]: r,
});
}
if (
highlightedHeaderCells &&
@@ -631,6 +642,7 @@ export class TableRenderer extends React.Component {
i,
this.props.tableOptions.clickRowHeaderCallback,
)}
onContextMenu={handleContextMenu}
>
{displayHeaderCell(
needRowToggle,

View File

@@ -26,8 +26,8 @@ import {
NumberFormatter,
QueryFormMetric,
QueryFormColumn,
BinaryQueryObjectFilterClause,
TimeGranularity,
ContextMenuFilters,
} from '@superset-ui/core';
import { ColorFormatters } from '@superset-ui/chart-controls';
@@ -77,7 +77,7 @@ interface PivotTableCustomizeProps {
onContextMenu?: (
clientX: number,
clientY: number,
filters?: BinaryQueryObjectFilterClause[],
filters?: ContextMenuFilters,
) => void;
timeGrainSqla?: TimeGranularity;
}