diff --git a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx index 6d141f941c..b2e47cc53c 100644 --- a/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx +++ b/superset-frontend/src/components/ReportModal/HeaderReportDropdown/index.tsx @@ -18,6 +18,7 @@ */ import React, { useState, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; +import { isEmpty } from 'lodash'; import { t, SupersetTheme, @@ -103,6 +104,9 @@ export interface HeaderReportProps { showReportSubMenu?: boolean; } +// Same instance to be used in useEffects +const EMPTY_OBJECT = {}; + export default function HeaderReportDropDown({ dashboardId, chart, @@ -116,7 +120,10 @@ export default function HeaderReportDropDown({ const resourceType = dashboardId ? CreationMethod.DASHBOARDS : CreationMethod.CHARTS; - return reportSelector(state, resourceType, dashboardId || chart?.id); + return ( + reportSelector(state, resourceType, dashboardId || chart?.id) || + EMPTY_OBJECT + ); }); const isReportActive: boolean = report?.active || false; @@ -133,6 +140,12 @@ export default function HeaderReportDropDown({ // this is in the case that there is an anonymous user. return false; } + + // Cannot add reports if the resource is not saved + if (!(dashboardId || chart?.id)) { + return false; + } + const roles = Object.keys(user.roles || []); const permissions = roles.map(key => user.roles[key].filter( @@ -200,7 +213,21 @@ export default function HeaderReportDropDown({ }; const textMenu = () => - report ? ( + isEmpty(report) ? ( + + + {DropdownItemExtension ? ( + +
{t('Set up an email report')}
+ +
+ ) : ( + t('Set up an email report') + )} +
+ +
+ ) : ( isDropdownVisible && ( ) - ) : ( - - - {DropdownItemExtension ? ( - -
{t('Set up an email report')}
- -
- ) : ( - t('Set up an email report') - )} -
- -
); const menu = () => ( @@ -260,7 +273,17 @@ export default function HeaderReportDropDown({ ); const iconMenu = () => - report ? ( + isEmpty(report) ? ( + setShowModal(true)} + > + + + ) : ( <> - ) : ( - setShowModal(true)} - > - - ); return ( diff --git a/superset-frontend/src/components/ReportModal/index.tsx b/superset-frontend/src/components/ReportModal/index.tsx index 9f9596e2ff..345d8b8224 100644 --- a/superset-frontend/src/components/ReportModal/index.tsx +++ b/superset-frontend/src/components/ReportModal/index.tsx @@ -93,6 +93,9 @@ type ReportObjectState = Partial & { isSubmitting?: boolean; }; +// Same instance to be used in useEffects +const EMPTY_OBJECT = {}; + function ReportModal({ onHide, show = false, @@ -147,7 +150,10 @@ function ReportModal({ const resourceType = dashboardId ? CreationMethod.DASHBOARDS : CreationMethod.CHARTS; - return reportSelector(state, resourceType, dashboardId || chart?.id); + return ( + reportSelector(state, resourceType, dashboardId || chart?.id) || + EMPTY_OBJECT + ); }); const isEditMode = report && Object.keys(report).length; diff --git a/superset-frontend/src/reports/actions/reports.js b/superset-frontend/src/reports/actions/reports.js index 96a435ec5d..45edc90129 100644 --- a/superset-frontend/src/reports/actions/reports.js +++ b/superset-frontend/src/reports/actions/reports.js @@ -143,6 +143,8 @@ export function toggleActive(report, isActive) { }; } +export const DELETE_REPORT = 'DELETE_REPORT'; + export function deleteActiveReport(report) { return function deleteActiveReportThunk(dispatch) { return SupersetClient.delete({ @@ -152,7 +154,7 @@ export function deleteActiveReport(report) { dispatch(addDangerToast(t('Your report could not be deleted'))); }) .finally(() => { - dispatch(structureFetchAction); + dispatch({ type: DELETE_REPORT, report }); dispatch(addSuccessToast(t('Deleted: %s', report.name))); }); }; diff --git a/superset-frontend/src/reports/reducers/reports.js b/superset-frontend/src/reports/reducers/reports.js index 1896250f5c..823660b645 100644 --- a/superset-frontend/src/reports/reducers/reports.js +++ b/superset-frontend/src/reports/reducers/reports.js @@ -18,7 +18,13 @@ */ /* eslint-disable camelcase */ // eslint-disable-next-line import/no-extraneous-dependencies -import { SET_REPORT, ADD_REPORT, EDIT_REPORT } from '../actions/reports'; +import { omit } from 'lodash'; +import { + SET_REPORT, + ADD_REPORT, + EDIT_REPORT, + DELETE_REPORT, +} from '../actions/reports'; export default function reportsReducer(state = {}, action) { const actionHandlers = { @@ -78,6 +84,17 @@ export default function reportsReducer(state = {}, action) { }, }; }, + + [DELETE_REPORT]() { + const { report } = action; + const reportTypeId = report.dashboard || report.chart; + return { + ...state, + [report.creation_method]: { + ...omit(state[report.creation_method], reportTypeId), + }, + }; + }, }; if (action.type in actionHandlers) { diff --git a/superset-frontend/src/views/CRUD/hooks.ts b/superset-frontend/src/views/CRUD/hooks.ts index dfcf23e190..91af5817b4 100644 --- a/superset-frontend/src/views/CRUD/hooks.ts +++ b/superset-frontend/src/views/CRUD/hooks.ts @@ -867,5 +867,5 @@ export const reportSelector = ( if (resourceId) { return state.reports[resourceType]?.[resourceId]; } - return {}; + return null; };