amaannawab923 commented on code in PR #33831: URL: https://github.com/apache/superset/pull/33831#discussion_r2239798038
########## 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)); + + const dataMask = { + extraFormData: {}, + filterState: { + value: + item.customization?.defaultDataMask?.filterState?.value || [], + }, + ownState: { + column: item.customization.column, + }, + }; + dispatch(updateDataMask(customizationFilterId, dataMask)); + } else { + dispatch(removeDataMask(customizationFilterId)); + } + }); + }; +} + +export const SET_CHART_CUSTOMIZATION_DATA_LOADING = + 'SET_CHART_CUSTOMIZATION_DATA_LOADING'; +export interface SetChartCustomizationDataLoading { + type: typeof SET_CHART_CUSTOMIZATION_DATA_LOADING; + itemId: string; + isLoading: boolean; +} + +export function setChartCustomizationDataLoading( + itemId: string, + isLoading: boolean, +): SetChartCustomizationDataLoading { + return { + type: SET_CHART_CUSTOMIZATION_DATA_LOADING, + itemId, + isLoading, + }; +} + +export const SET_CHART_CUSTOMIZATION_DATA = 'SET_CHART_CUSTOMIZATION_DATA'; +export interface SetChartCustomizationData { + type: typeof SET_CHART_CUSTOMIZATION_DATA; + itemId: string; + data: FilterOption[]; +} + +export function setChartCustomizationData( + itemId: string, + data: FilterOption[], +): SetChartCustomizationData { + return { + type: SET_CHART_CUSTOMIZATION_DATA, + itemId, + data, + }; +} + +export function loadChartCustomizationData( + itemId: string, + datasetId: string, + columnName: string | string[], +): ThunkAction<Promise<void>, RootState, null, AnyAction> { + return async (dispatch: ThunkDispatch<RootState, null, AnyAction>) => { + if (!datasetId || !columnName) { + return; + } + + const actualColumnName = Array.isArray(columnName) + ? columnName[0] + : columnName; + + if (!actualColumnName) { + return; + } + + dispatch(setChartCustomizationDataLoading(itemId, true)); + + try { + const formData = getFormData({ + datasetId: Number(datasetId), + groupby: actualColumnName, + dashboardId: 0, + filterType: 'filter_select', + }); + + const response = await getChartDataRequest({ Review Comment: Why are we firing an Api request of getChartDataRequest here ... I did see a Refresh Chart as well earlier ... Wouldnt this cause multiple api calls -- 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