Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions UPDATING.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ assists people when migrating to a new version.
- [32317](https://github.com/apache/superset/pull/32317) The horizontal filter bar feature is now out of testing/beta development and its feature flag `HORIZONTAL_FILTER_BAR` has been removed.
- [31590](https://github.com/apache/superset/pull/31590) Marks the begining of intricate work around supporting dynamic Theming, and breaks support for [THEME_OVERRIDES](https://github.com/apache/superset/blob/732de4ac7fae88e29b7f123b6cbb2d7cd411b0e4/superset/config.py#L671) in favor of a new theming system based on AntD V5. Likely this will be in disrepair until settling over the 5.x lifecycle.
- [32432](https://github.com/apache/superset/pull/31260) Moves the List Roles FAB view to the frontend and requires `FAB_ADD_SECURITY_API` to be enabled in the configuration and `superset init` to be executed.
- [34319](https://github.com/apache/superset/pull/34319) Drill to Detail and Drill By is now supported in Embedded mode, and also with the `DASHBOARD_RBAC` FF. If you don't want to expose these features in Embedded / `DASHBOARD_RBAC`, make sure the roles used for Embedded / `DASHBOARD_RBAC`don't have the required permissions to perform D2D actions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we highlight what the roles are to turn this on/off?

Copy link
Contributor Author

@Vitor-Avila Vitor-Avila Aug 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eschutho I think these are configureable by deployment, so unsure if we could highlight it. IIRC the embedded role is set in superset_config.py via the GUEST_ROLE_NAME config, then for DASHBOARD_RBAC access users can use any role they had created in the Superset UI.
Let me know if you want me to rephrase this in a better way.


## 5.0.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,52 @@ import {
interceptFormDataKey,
} from '../explore/utils';

const interceptDrillInfo = () => {
cy.intercept('GET', '**/api/v1/dataset/*/drill_info/*', {
statusCode: 200,
body: {
result: {
id: 1,
changed_on_humanized: '2 days ago',
created_on_humanized: 'a week ago',
table_name: 'birth_names',
changed_by: {
first_name: 'Admin',
last_name: 'User',
},
created_by: {
first_name: 'Admin',
last_name: 'User',
},
owners: [
{
first_name: 'Admin',
last_name: 'User',
},
],
columns: [
{
column_name: 'gender',
verbose_name: null,
},
{
column_name: 'state',
verbose_name: null,
},
{
column_name: 'name',
verbose_name: null,
},
{
column_name: 'ds',
verbose_name: null,
},
],
},
},
}).as('drillInfo');
};

const closeModal = () => {
cy.get('body').then($body => {
if ($body.find('[data-test="close-drill-by-modal"]').length) {
Expand Down Expand Up @@ -62,6 +108,7 @@ const drillBy = (targetDrillByColumn: string, isLegacy = false) => {

cy.get(
'.ant-dropdown-menu-submenu:not(.ant-dropdown-menu-submenu-hidden) [data-test="drill-by-submenu"]',
{ timeout: 15000 },
)
.should('be.visible')
.find('[role="menuitem"]')
Expand Down Expand Up @@ -235,12 +282,14 @@ describe('Drill by modal', () => {
closeModal();
});
before(() => {
interceptDrillInfo();
cy.visit(SUPPORTED_CHARTS_DASHBOARD);
});

describe('Modal actions + Table', () => {
before(() => {
closeModal();
interceptDrillInfo();
openTopLevelTab('Tier 1');
SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad);
});
Expand Down Expand Up @@ -389,6 +438,7 @@ describe('Drill by modal', () => {
describe('Tier 1 charts', () => {
before(() => {
closeModal();
interceptDrillInfo();
openTopLevelTab('Tier 1');
SUPPORTED_TIER1_CHARTS.forEach(waitForChartLoad);
});
Expand Down Expand Up @@ -552,6 +602,7 @@ describe('Drill by modal', () => {
describe('Tier 2 charts', () => {
before(() => {
closeModal();
interceptDrillInfo();
openTopLevelTab('Tier 2');
SUPPORTED_TIER2_CHARTS.forEach(waitForChartLoad);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import {
ReactNode,
RefObject,
useCallback,
useEffect,
useImperativeHandle,
useMemo,
useState,
} from 'react';
import ReactDOM from 'react-dom';
Expand All @@ -35,7 +37,9 @@ import {
ensureIsArray,
FeatureFlag,
getChartMetadataRegistry,
getExtensionsRegistry,
isFeatureEnabled,
logging,
QueryFormData,
t,
useTheme,
Expand All @@ -48,6 +52,10 @@ import { updateDataMask } from 'src/dataMask/actions';
import DrillByModal from 'src/components/Chart/DrillBy/DrillByModal';
import { useVerboseMap } from 'src/hooks/apiResources/datasets';
import { Dataset } from 'src/components/Chart/types';
import {
cachedSupersetGet,
supersetGetCache,
} from 'src/utils/cachedSupersetGet';
import { DrillDetailMenuItems } from '../DrillDetail';
import { getMenuAdjustedY } from '../utils';
import { MenuItemTooltip } from '../DisabledMenuItemTooltip';
Expand Down Expand Up @@ -99,6 +107,9 @@ const ChartContextMenu = (
const crossFiltersEnabled = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.crossFiltersEnabled,
);
const dashboardId = useSelector<RootState, number>(
({ dashboardInfo }) => dashboardInfo.id,
);
const [openKeys, setOpenKeys] = useState<Key[]>([]);

const [modalFilters, setFilters] = useState<BinaryQueryObjectFilterClause[]>(
Expand All @@ -121,6 +132,7 @@ const ChartContextMenu = (
const [drillByColumn, setDrillByColumn] = useState<Column>();
const [showDrillByModal, setShowDrillByModal] = useState(false);
const [dataset, setDataset] = useState<Dataset>();
const [isLoadingDataset, setIsLoadingDataset] = useState(false);
const verboseMap = useVerboseMap(dataset);

const closeContextMenu = useCallback(() => {
Expand All @@ -129,12 +141,15 @@ const ChartContextMenu = (
onClose();
}, [onClose]);

const handleDrillBy = useCallback((column: Column, dataset: Dataset) => {
const handleDrillBy = useCallback((column: Column) => {
setDrillByColumn(column);
setDataset(dataset); // Save dataset when drilling
setShowDrillByModal(true);
}, []);

const loadDrillByOptionsExtension = getExtensionsRegistry().get(
'load.drillby.options',
);

const handleCloseDrillByModal = useCallback(() => {
setShowDrillByModal(false);
}, []);
Expand All @@ -151,6 +166,75 @@ const ChartContextMenu = (
canDrillBy &&
isDisplayed(ContextMenuItem.DrillBy);

useEffect(() => {
async function fetchDataset() {
if (!visible || dataset || (!showDrillBy && !showDrillToDetail)) return;

const datasetId = Number(formData.datasource.split('__')[0]);
try {
setIsLoadingDataset(true);
let response;

if (loadDrillByOptionsExtension) {
response = await loadDrillByOptionsExtension(datasetId, formData);
} else {
const endpoint = `/api/v1/dataset/${datasetId}/drill_info/?q=(dashboard_id:${dashboardId})`;
response = await cachedSupersetGet({ endpoint });
}

const { json } = response;
const { result } = json;

setDataset(result);
} catch (error) {
logging.error('Failed to load dataset:', error);
supersetGetCache.delete(`/api/v1/dataset/${datasetId}/drill_info/`);
Comment on lines +189 to +191

This comment was marked as resolved.

} finally {
setIsLoadingDataset(false);
}
}

fetchDataset();
}, [
visible,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to add dataset here as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've thought so too and checked with Claude and it advised not to, because this block also does setDataset(result) so if dataset was a dependency it would re-render one more time as the dataset value would change with setDataset(result).

From my manual tests it's working properly.

showDrillBy,
showDrillToDetail,
formData.datasource,
loadDrillByOptionsExtension,
dashboardId,
]);

// Compute filteredDataset with all columns returned + a filtered list of valid drillable options
const filteredDataset = useMemo(() => {
if (!dataset || !showDrillBy) return dataset;

const filteredColumns = ensureIsArray(dataset.columns).filter(
column =>
// If using an extension, also filter by column.groupby since the extension might not do this
(!loadDrillByOptionsExtension || column.groupby) &&
!ensureIsArray(
formData[filters?.drillBy?.groupbyFieldName ?? ''],
).includes(column.column_name) &&
column.column_name !== formData.x_axis &&
ensureIsArray(additionalConfig?.drillBy?.excludedColumns)?.every(
excludedCol => excludedCol.column_name !== column.column_name,
),
);

return {
...dataset,
drillable_columns: filteredColumns,
};
}, [
dataset,
showDrillBy,
filters?.drillBy?.groupbyFieldName,
formData.x_axis,
formData[filters?.drillBy?.groupbyFieldName ?? ''],
additionalConfig?.drillBy?.excludedColumns,
loadDrillByOptionsExtension,
]);

const showCrossFilters = isDisplayed(ContextMenuItem.CrossFilter);

const isCrossFilteringSupportedByChart = getChartMetadataRegistry()
Expand Down Expand Up @@ -254,6 +338,8 @@ const ChartContextMenu = (
onSelection={onSelection}
submenuIndex={showCrossFilters ? 2 : 1}
setShowModal={setDrillModalIsOpen}
dataset={filteredDataset}
isLoadingDataset={isLoadingDataset}
{...(additionalConfig?.drillToDetail || {})}
/>,
);
Expand All @@ -277,6 +363,8 @@ const ChartContextMenu = (
open={openKeys.includes('drill-by-submenu')}
key="drill-by-submenu"
onDrillBy={handleDrillBy}
dataset={filteredDataset}
isLoadingDataset={isLoadingDataset}
{...(additionalConfig?.drillBy || {})}
/>,
);
Expand Down Expand Up @@ -359,6 +447,7 @@ const ChartContextMenu = (
onHideModal={() => {
setDrillModalIsOpen(false);
}}
dataset={filteredDataset}
/>
)}
{showDrillByModal && drillByColumn && dataset && filters?.drillBy && (
Expand All @@ -367,7 +456,7 @@ const ChartContextMenu = (
drillByConfig={filters?.drillBy}
formData={formData}
onHideModal={handleCloseDrillByModal}
dataset={{ ...dataset!, verbose_map: verboseMap }}
dataset={{ ...filteredDataset!, verbose_map: verboseMap }}
canDownload={canDownload}
/>
)}
Expand Down
Loading
Loading