amaannawab923 commented on code in PR #33831: URL: https://github.com/apache/superset/pull/33831#discussion_r2239794881
########## superset-frontend/src/dashboard/actions/dashboardInfo.ts: ########## @@ -188,43 +288,403 @@ export function saveFilterBarOrientation(orientation: FilterBarOrientation) { dispatch(onSave(lastModifiedTime)); } } catch (errorObject) { - const errorText = await getErrorText(errorObject, 'dashboard'); - dispatch(addDangerToast(errorText)); + const { error } = await getClientErrorObject(errorObject); + dispatch( + addDangerToast( + t( + 'Sorry, there was an error saving this dashboard: %s', + error || 'Bad Request', + ), + ), + ); throw errorObject; } }; } export function saveCrossFiltersSetting(crossFiltersEnabled: boolean) { - return async (dispatch: Dispatch, getState: () => RootState) => { + return async function saveCrossFiltersSettingThunk( + dispatch: Dispatch, + getState: () => RootState, + ) { const { id, metadata } = getState().dashboardInfo; - const updateDashboard = makeApi< - Partial<DashboardInfo>, - { result: Partial<DashboardInfo>; last_modified_time: number } - >({ - method: 'PUT', - endpoint: `/api/v1/dashboard/${id}`, - }); + dispatch(setCrossFiltersEnabled(crossFiltersEnabled)); + const updateDashboard = createUpdateDashboardApi(id); + try { const response = await updateDashboard({ json_metadata: JSON.stringify({ ...metadata, cross_filters_enabled: crossFiltersEnabled, }), }); + dispatch( + dashboardInfoChanged({ + metadata: JSON.parse(response.result.json_metadata || '{}'), + }), + ); + return response; + } catch (err) { + dispatch(addDangerToast(t('Failed to save cross-filters setting'))); + throw err; + } + }; +} + +export function saveChartCustomization( + chartCustomizationItems: ChartCustomizationSavePayload[], +): ThunkAction<Promise<any>, RootState, null, AnyAction> { + return async function ( + dispatch: ThunkDispatch<RootState, null, AnyAction>, + getState: () => RootState, + ) { + const { id, metadata, json_metadata } = getState().dashboardInfo; + + const currentState = getState(); + const currentChartCustomizationItems = + currentState.dashboardInfo.metadata?.chart_customization_config || []; + + const existingItemsMap = new Map( + currentChartCustomizationItems.map(item => [item.id, item]), + ); + + const updatedItemsMap = new Map(existingItemsMap); + + chartCustomizationItems.forEach(newItem => { + if (newItem.removed) { + updatedItemsMap.delete(newItem.id); + } else { + const chartCustomizationItem: ChartCustomizationItem = { + id: newItem.id, + title: newItem.title, + removed: newItem.removed, + chartId: newItem.chartId, + customization: newItem.customization, + }; + updatedItemsMap.set(newItem.id, chartCustomizationItem); + } + }); + + const simpleItems = Array.from(updatedItemsMap.values()); + + const updateDashboard = createUpdateDashboardApi(id); + + try { + let parsedMetadata: any = {}; + try { + parsedMetadata = json_metadata ? JSON.parse(json_metadata) : metadata; + } catch (e) { + console.error('Error parsing json_metadata:', e); + parsedMetadata = metadata || {}; + } + + const updatedMetadata = { + ...parsedMetadata, + native_filter_configuration: ( + parsedMetadata.native_filter_configuration || [] + ).filter( + (item: any) => + !( + item.type === 'CHART_CUSTOMIZATION' && + item.id === 'chart_customization_groupby' + ), + ), + chart_customization_config: simpleItems, + }; + + const response = await updateDashboard({ + json_metadata: JSON.stringify(updatedMetadata), + }); + const updatedDashboard = response.result; const lastModifiedTime = response.last_modified_time; + if (updatedDashboard.json_metadata) { - const metadata = JSON.parse(updatedDashboard.json_metadata); - dispatch(setCrossFiltersEnabled(metadata.cross_filters_enabled)); + dispatch(setChartCustomization(simpleItems)); + + const removedItems = currentChartCustomizationItems.filter( + existingItem => !updatedItemsMap.has(existingItem.id), + ); + + removedItems.forEach(removedItem => { + const customizationFilterId = `chart_customization_${removedItem.id}`; + dispatch(removeDataMask(customizationFilterId)); + }); + + simpleItems.forEach(item => { + const customizationFilterId = `chart_customization_${item.id}`; + + if (item.customization?.column) { + dispatch(removeDataMask(customizationFilterId)); + + const dataMask = { + extraFormData: {}, + filterState: { + value: + item.customization?.defaultDataMask?.filterState?.value || [], + }, + ownState: { + column: item.customization.column, + }, + }; + dispatch(updateDataMask(customizationFilterId, dataMask)); + } else { + dispatch(removeDataMask(customizationFilterId)); + } + }); + + const state = getState(); + const affectedChartIds = getAffectedChartIdsFromCustomization( + simpleItems, + state, + ); + + removedItems.forEach(removedItem => { + if (removedItem.chartId) { + affectedChartIds.push(removedItem.chartId); + } + }); + + const uniqueAffectedChartIds = [...new Set(affectedChartIds)]; + + uniqueAffectedChartIds.forEach(chartId => { + const chart = state.charts[chartId]; + if ( + chart?.latestQueryFormData && + Object.keys(chart.latestQueryFormData).length > 0 + ) { + dispatch(refreshChart(chartId)); + } + }); } + if (lastModifiedTime) { dispatch(onSave(lastModifiedTime)); } + + return response; } catch (errorObject) { - const errorText = await getErrorText(errorObject, 'dashboard'); - dispatch(addDangerToast(errorText)); + console.error('Error saving chart customization:', errorObject); + const { error } = await getClientErrorObject(errorObject); + dispatch( + addDangerToast(error || t('Failed to save chart customization')), + ); throw errorObject; } }; } + +export const INITIALIZE_CHART_CUSTOMIZATION = 'INITIALIZE_CHART_CUSTOMIZATION'; +export interface InitializeChartCustomization { + type: typeof INITIALIZE_CHART_CUSTOMIZATION; + chartCustomizationItems: ChartCustomizationItem[]; +} + +export function initializeChartCustomization( + chartCustomizationItems: ChartCustomizationItem[], +): ThunkAction<void, RootState, null, AnyAction> { + return (dispatch: ThunkDispatch<RootState, null, AnyAction>) => { + dispatch({ + type: INITIALIZE_CHART_CUSTOMIZATION, + chartCustomizationItems, + }); + + chartCustomizationItems.forEach(item => { + const customizationFilterId = `chart_customization_${item.id}`; + + if (item.customization?.column) { + dispatch(removeDataMask(customizationFilterId)); Review Comment: Why are we manually removing data Mask of an object ... i dont think that datamask should be related to the Chart Customisation item -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@superset.apache.org For additional commands, e-mail: notifications-h...@superset.apache.org