Compare commits

..

8 Commits

Author SHA1 Message Date
Elizabeth Thompson
3e152d9bb7 fix(views): add new_target to deprecated explore_json_data endpoint (#41771) 2026-07-04 15:01:42 -07:00
Pawan
004c401c97 refactor(dashboard): rename supersetCanCSV to supersetCanDownload (#24290) (#39118)
Co-authored-by: jaymasiwal <jaymasiwal@users.noreply.github.com>
2026-07-04 13:06:14 -07:00
dependabot[bot]
a9aabdaedf chore(deps): bump gunicorn from 25.3.0 to 26.0.0 (#41761)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-04 10:03:16 -07:00
Đỗ Trọng Hải
210389478b fix(test): change regex for RTL to retrieve button used for filter removal (#41767)
Signed-off-by: hainenber <dotronghai96@gmail.com>
2026-07-04 09:58:30 -07:00
dependabot[bot]
43f2816240 chore(deps-dev): update ydb-sqlglot-plugin requirement from >=0.2.5 to >=0.2.8 (#41764)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 15:04:59 +07:00
dependabot[bot]
c3fe0a40eb chore(deps-dev): bump mysqlclient from 2.2.6 to 2.2.8 (#41760)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-04 14:53:22 +07:00
dependabot[bot]
71ac6c64e2 chore(deps): bump rison from 2.0.0 to 2.0.1 (#41762)
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-07-04 14:52:53 +07:00
dependabot[bot]
81a437826f chore(deps-dev): update kylinpy requirement from <2.9,>=2.8.1 to >=2.8.4,<2.9 (#41765)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-04 14:52:36 +07:00
16 changed files with 57 additions and 41 deletions

View File

@@ -64,7 +64,7 @@ dependencies = [
"flask-wtf>=1.3.0, <2.0",
"geopy",
"greenlet<=3.5.1, >=3.5.1",
"gunicorn>=25.3.0, <26; sys_platform != 'win32'",
"gunicorn>=26.0.0, <27; sys_platform != 'win32'",
"hashids>=1.3.1, <2",
# holidays>=0.45 required for security fix
"holidays>=0.45, <1",
@@ -101,7 +101,7 @@ dependencies = [
"pyyaml>=6.0.3, <7.0.0",
"PyJWT>=2.4.0, <3.0",
"redis>=5.0.0, <6.0",
"rison>=2.0.0, <3.0",
"rison>=2.0.1, <3.0",
"selenium>=4.45.0, <5.0",
"shillelagh[gsheetsapi]>=1.4.4, <2.0",
"sshtunnel>=0.4.0, <0.5",
@@ -174,11 +174,11 @@ hive = [
]
impala = ["impyla>0.16.2, <0.23"]
kusto = ["sqlalchemy-kusto>=3.1.2, <4"]
kylin = ["kylinpy>=2.8.1, <2.9"]
kylin = ["kylinpy>=2.8.4, <2.9"]
mssql = ["pymssql>=2.3.13, <3"]
# motherduck is an alias for duckdb - MotherDuck works via the duckdb driver
motherduck = ["apache-superset[duckdb]"]
mysql = ["mysqlclient>=2.1.0, <3"]
mysql = ["mysqlclient>=2.2.8, <3"]
ocient = [
"sqlalchemy-ocient>=1.0.0",
"pyocient>=1.0.15, <4",
@@ -216,7 +216,7 @@ netezza = ["nzalchemy>=11.0.2, < 11.2"]
starrocks = ["starrocks>=1.3.3, <2"]
doris = ["pydoris>=1.0.0, <2.0.0"]
oceanbase = ["oceanbase_py>=0.0.1.2"]
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.5"]
ydb = ["ydb-sqlalchemy>=0.1.22", "ydb-sqlglot-plugin>=0.2.8"]
development = [
# no bounds for apache-superset-extensions-cli until a stable version
"apache-superset-extensions-cli",

View File

@@ -169,7 +169,7 @@ greenlet==3.5.1
# apache-superset (pyproject.toml)
# shillelagh
# sqlalchemy
gunicorn==25.3.0
gunicorn==26.0.0
# via apache-superset (pyproject.toml)
h11==0.16.0
# via wsproto
@@ -369,7 +369,7 @@ rfc3339-validator==0.1.4
# via openapi-schema-validator
rich==13.9.4
# via flask-limiter
rison==2.0.0
rison==2.0.1
# via apache-superset (pyproject.toml)
rpds-py==0.25.0
# via

View File

@@ -393,7 +393,7 @@ grpcio==1.81.1
# grpcio-status
grpcio-status==1.60.1
# via google-api-core
gunicorn==25.3.0
gunicorn==26.0.0
# via
# -c requirements/base-constraint.txt
# apache-superset
@@ -572,7 +572,7 @@ msgspec==0.19.0
# via
# -c requirements/base-constraint.txt
# flask-session
mysqlclient==2.2.6
mysqlclient==2.2.8
# via apache-superset
nh3==0.3.5
# via
@@ -913,7 +913,7 @@ rich==13.9.4
# rich-rst
rich-rst==1.3.1
# via cyclopts
rison==2.0.0
rison==2.0.1
# via
# -c requirements/base-constraint.txt
# apache-superset

View File

@@ -45112,7 +45112,7 @@
"@deck.gl/extensions": "~9.2.9",
"@deck.gl/geo-layers": "~9.2.5",
"@deck.gl/layers": "~9.2.5",
"@deck.gl/mapbox": "^9.3.5",
"@deck.gl/mapbox": "~9.3.5",
"@deck.gl/mesh-layers": "~9.2.5",
"@luma.gl/constants": "~9.2.5",
"@luma.gl/core": "~9.2.5",

View File

@@ -355,7 +355,7 @@ export const hydrateDashboard =
'Superset',
roles,
),
superset_can_csv: findPermission('can_csv', 'Superset', roles),
superset_can_download: findPermission('can_csv', 'Superset', roles),
common: {
// legacy, please use state.common instead
conf: common?.conf,

View File

@@ -35,7 +35,7 @@ jest.mock('src/dashboard/components/SliceHeaderControls', () => ({
data-cached-dttm={props.cachedDttm}
data-updated-dttm={props.updatedDttm}
data-superset-can-explore={props.supersetCanExplore}
data-superset-can-csv={props.supersetCanCSV}
data-superset-can-download={props.supersetCanDownload}
data-component-id={props.componentId}
data-dashboard-id={props.dashboardId}
data-is-full-size={props.isFullSize}
@@ -144,7 +144,7 @@ const createProps = (overrides: any = {}) => ({
isExpanded: false,
sliceName: 'Vaccine Candidates per Phase',
supersetCanExplore: true,
supersetCanCSV: true,
supersetCanDownload: true,
slice: {
slice_id: MOCKED_CHART_ID,
slice_url: `/explore/?form_data=%7B%22slice_id%22%3A%20${MOCKED_CHART_ID}%7D`,
@@ -222,7 +222,7 @@ test('Should render - default props', () => {
delete props.isExpanded;
delete props.sliceName;
delete props.supersetCanExplore;
delete props.supersetCanCSV;
delete props.supersetCanDownload;
render(<SliceHeader {...props} />, {
useRedux: true,
@@ -250,7 +250,7 @@ test('Should render default props and "call" actions', () => {
delete props.isExpanded;
delete props.sliceName;
delete props.supersetCanExplore;
delete props.supersetCanCSV;
delete props.supersetCanDownload;
render(<SliceHeader {...props} />, {
useRedux: true,
@@ -459,7 +459,7 @@ test('Correct props to "SliceHeaderControls"', () => {
'false',
);
expect(screen.getByTestId('SliceHeaderControls')).toHaveAttribute(
'data-superset-can-csv',
'data-superset-can-download',
'true',
);
expect(screen.getByTestId('SliceHeaderControls')).toHaveAttribute(

View File

@@ -157,7 +157,7 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
sliceName = '',
supersetCanExplore = false,
supersetCanShare = false,
supersetCanCSV = false,
supersetCanDownload = false,
exportPivotCSV,
exportFullCSV,
exportFullXLSX,
@@ -367,7 +367,7 @@ const SliceHeader = forwardRef<HTMLDivElement, SliceHeaderProps>(
exportFullXLSX={exportFullXLSX}
supersetCanExplore={supersetCanExplore}
supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}
supersetCanDownload={supersetCanDownload}
componentId={componentId}
dashboardId={dashboardId}
addSuccessToast={addSuccessToast}

View File

@@ -98,7 +98,7 @@ const buildProps = (): SliceHeaderControlsProps =>
cachedDttm: [''],
updatedDttm: 0,
supersetCanExplore: true,
supersetCanCSV: true,
supersetCanDownload: true,
componentId: 'CHART-subdir',
dashboardId: 26,
isFullSize: false,

View File

@@ -87,7 +87,7 @@ const createProps = (viz_type = VizType.Sunburst) =>
cachedDttm: [''],
updatedDttm: 1617213803803,
supersetCanExplore: true,
supersetCanCSV: true,
supersetCanDownload: true,
componentId: 'CHART-fYo7IyvKZQ',
dashboardId: 26,
isFullSize: false,

View File

@@ -141,7 +141,7 @@ export interface SliceHeaderControlsProps {
supersetCanExplore?: boolean;
supersetCanShare?: boolean;
supersetCanCSV?: boolean;
supersetCanDownload?: boolean;
crossFiltersEnabled?: boolean;
}
@@ -519,7 +519,7 @@ const SliceHeaderControls = (
dataSize={20}
isRequest
isVisible
canDownload={!!props.supersetCanCSV}
canDownload={!!props.supersetCanDownload}
columnDisplayNames={datasetWithVerboseMap?.verbose_map}
/>
}
@@ -562,7 +562,7 @@ const SliceHeaderControls = (
newMenuItems.push(shareMenuItems);
}
if (props.supersetCanCSV) {
if (props.supersetCanDownload) {
newMenuItems.push({
type: 'submenu',
key: MenuKeys.Download,
@@ -593,7 +593,7 @@ const SliceHeaderControls = (
icon: <Icons.FileOutlined css={dropdownIconsStyles} />,
},
...(isFeatureEnabled(FeatureFlag.AllowFullCsvExport) &&
props.supersetCanCSV &&
props.supersetCanDownload &&
isTable
? [
{

View File

@@ -57,7 +57,7 @@ export interface SliceHeaderControlsProps {
supersetCanExplore?: boolean;
supersetCanShare?: boolean;
supersetCanCSV?: boolean;
supersetCanDownload?: boolean;
crossFiltersEnabled?: boolean;
}

View File

@@ -89,7 +89,7 @@ const defaultState = {
id: props.dashboardId,
superset_can_explore: false,
superset_can_share: false,
superset_can_csv: false,
superset_can_download: false,
common: { conf: { SUPERSET_WEBSERVER_TIMEOUT: 0, SQL_MAX_ROW: 666 } },
},
dashboardLayout: {
@@ -181,7 +181,10 @@ test('should call exportChart when exportCSV is clicked', async () => {
const { findByText, getByRole } = setup(
{},
{
dashboardInfo: { ...defaultState.dashboardInfo, superset_can_csv: true },
dashboardInfo: {
...defaultState.dashboardInfo,
superset_can_download: true,
},
},
);
fireEvent.click(getByRole('button', { name: 'More Options' }));
@@ -211,7 +214,10 @@ test('should call exportChart with row_limit props.maxRows when exportFullCSV is
const { findByText, getByRole } = setup(
{},
{
dashboardInfo: { ...defaultState.dashboardInfo, superset_can_csv: true },
dashboardInfo: {
...defaultState.dashboardInfo,
superset_can_download: true,
},
},
);
fireEvent.click(getByRole('button', { name: 'More Options' }));
@@ -239,7 +245,10 @@ test('should call exportChart when exportXLSX is clicked', async () => {
const { findByText, getByRole } = setup(
{},
{
dashboardInfo: { ...defaultState.dashboardInfo, superset_can_csv: true },
dashboardInfo: {
...defaultState.dashboardInfo,
superset_can_download: true,
},
},
);
fireEvent.click(getByRole('button', { name: 'More Options' }));
@@ -266,7 +275,10 @@ test('should call exportChart with row_limit props.maxRows when exportFullXLSX i
const { findByText, getByRole } = setup(
{},
{
dashboardInfo: { ...defaultState.dashboardInfo, superset_can_csv: true },
dashboardInfo: {
...defaultState.dashboardInfo,
superset_can_download: true,
},
},
);
fireEvent.click(getByRole('button', { name: 'More Options' }));

View File

@@ -218,9 +218,9 @@ const Chart = (props: ChartProps) => {
(state: RootState) =>
!!(state.dashboardInfo as JsonObject).superset_can_share,
);
const supersetCanCSV = useSelector(
const supersetCanDownload = useSelector(
(state: RootState) =>
!!(state.dashboardInfo as JsonObject).superset_can_csv,
!!(state.dashboardInfo as JsonObject).superset_can_download,
);
const timeout: number = useSelector(
(state: RootState) =>
@@ -710,7 +710,7 @@ const Chart = (props: ChartProps) => {
sliceName={props.sliceName}
supersetCanExplore={supersetCanExplore}
supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}
supersetCanDownload={supersetCanDownload}
componentId={props.componentId}
dashboardId={props.dashboardId}
filters={getActiveFilters() || EMPTY_OBJECT}

View File

@@ -181,6 +181,7 @@ const NAME_REQUIRED_REGEX = /^name is required$/i;
const COLUMN_REQUIRED_REGEX = /^column is required$/i;
const PRE_FILTER_REQUIRED_REGEX = /^pre-filter is required$/i;
const DEFAULT_VALUE_INVALID_REGEX = /choose.*valid value/i;
const REMOVE_FILTER_BUTTON_REGEX = /Remove filter/i;
const props: FiltersConfigModalProps = {
isOpen: true,
@@ -974,13 +975,15 @@ test('restores a deleted filter via the "Restore filter" button', async () => {
const filterContainer = screen.getByTestId('filter-title-container');
const firstTab = within(filterContainer).getAllByRole('tab')[0];
fireEvent.click(within(firstTab).getByRole('button', { name: /delete/i }));
fireEvent.click(
within(firstTab).getByRole('button', { name: REMOVE_FILTER_BUTTON_REGEX }),
);
expect(
await screen.findByText(/you have removed this filter/i),
).toBeInTheDocument();
const restoreButton = screen.getByTestId('restore-filter-button');
await userEvent.click(restoreButton);
userEvent.click(restoreButton);
await waitFor(() => {
expect(
@@ -1009,11 +1012,13 @@ test('undoes a filter deletion via the sidebar "Undo?" link', async () => {
const filterContainer = screen.getByTestId('filter-title-container');
const firstTab = within(filterContainer).getAllByRole('tab')[0];
fireEvent.click(within(firstTab).getByRole('button', { name: /delete/i }));
fireEvent.click(
within(firstTab).getByRole('button', { name: REMOVE_FILTER_BUTTON_REGEX }),
);
const undoButton = await screen.findByTestId('undo-button');
expect(undoButton).toHaveTextContent(/undo\?/i);
await userEvent.click(undoButton);
userEvent.click(undoButton);
await waitFor(() => {
expect(

View File

@@ -22,7 +22,6 @@ import {
SupersetClient,
getClientErrorObject,
ClientErrorObject,
sanitizeHtml,
} from '@superset-ui/core';
import setupErrorMessages from 'src/setup/setupErrorMessages';
@@ -42,7 +41,7 @@ function showApiMessage(resp: ClientErrorObject) {
const severity = resp.severity || 'info';
$(template)
.addClass(`alert-${severity}`)
.append(sanitizeHtml(resp.message || ''))
.append(resp.message || '')
.appendTo($('#alert-container'));
}

View File

@@ -246,7 +246,7 @@ class Superset(BaseSupersetView):
@permission_name("explore_json")
@expose("/explore_json/data/<cache_key>", methods=("GET",))
@check_resource_permissions(check_explore_cache_perms)
@deprecated(eol_version="5.0.0")
@deprecated(eol_version="5.0.0", new_target="/api/v1/chart/data/<cache_key>")
def explore_json_data(self, cache_key: str) -> FlaskResponse:
"""Serves cached result data for async explore_json calls