You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by el...@apache.org on 2021/12/11 00:14:38 UTC
[superset] 01/03: fix(Dashboard): Copy dashboard with duplicating charts 500 error (#17707)
This is an automated email from the ASF dual-hosted git repository.
elizabeth pushed a commit to branch 1.4
in repository https://gitbox.apache.org/repos/asf/superset.git
commit 4c00bd4332860912ddecfa9ca02927b514621e3d
Author: Geido <60...@users.noreply.github.com>
AuthorDate: Fri Dec 10 01:25:01 2021 +0200
fix(Dashboard): Copy dashboard with duplicating charts 500 error (#17707)
* Fix copy dashboard with charts
* Fix Cypress test
---
.../src/dashboard/actions/dashboardState.js | 160 +++++++++++++++++++++
1 file changed, 160 insertions(+)
diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js
index 315ac7e..3eb193f 100644
--- a/superset-frontend/src/dashboard/actions/dashboardState.js
+++ b/superset-frontend/src/dashboard/actions/dashboardState.js
@@ -189,6 +189,166 @@ export function saveDashboardRequest(data, id, saveType) {
const serializedFilters = serializeActiveFilterValues(getActiveFilters());
// serialize filter scope for each filter field, grouped by filter id
const serializedFilterScopes = serializeFilterScopes(dashboardFilters);
+ const {
+ certified_by,
+ certification_details,
+ css,
+ dashboard_title,
+ owners,
+ roles,
+ slug,
+ } = data;
+
+ const hasId = item => item.id !== undefined;
+
+ // making sure the data is what the backend expects
+ const cleanedData = {
+ ...data,
+ certified_by: certified_by || '',
+ certification_details:
+ certified_by && certification_details ? certification_details : '',
+ css: css || '',
+ dashboard_title: dashboard_title || t('[ untitled dashboard ]'),
+ owners: ensureIsArray(owners).map(o => (hasId(o) ? o.id : o)),
+ roles: !isFeatureEnabled(FeatureFlag.DASHBOARD_RBAC)
+ ? undefined
+ : ensureIsArray(roles).map(r => (hasId(r) ? r.id : r)),
+ slug: slug || null,
+ metadata: {
+ ...data.metadata,
+ color_namespace: data.metadata?.color_namespace || undefined,
+ color_scheme: data.metadata?.color_scheme || '',
+ expanded_slices: data.metadata?.expanded_slices || {},
+ label_colors: data.metadata?.label_colors || {},
+ refresh_frequency: data.metadata?.refresh_frequency || 0,
+ timed_refresh_immune_slices:
+ data.metadata?.timed_refresh_immune_slices || [],
+ },
+ };
+
+ const handleChartConfiguration = () => {
+ const {
+ dashboardInfo: {
+ metadata: { chart_configuration = {} },
+ },
+ } = getState();
+ const chartConfiguration = Object.values(chart_configuration).reduce(
+ (prev, next) => {
+ // If chart removed from dashboard - remove it from metadata
+ if (
+ Object.values(layout).find(
+ layoutItem => layoutItem?.meta?.chartId === next.id,
+ )
+ ) {
+ return { ...prev, [next.id]: next };
+ }
+ return prev;
+ },
+ {},
+ );
+ return chartConfiguration;
+ };
+
+ const onCopySuccess = response => {
+ const lastModifiedTime = response.json.last_modified_time;
+ if (lastModifiedTime) {
+ dispatch(saveDashboardRequestSuccess(lastModifiedTime));
+ }
+ if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
+ const chartConfiguration = handleChartConfiguration();
+ dispatch(setChartConfiguration(chartConfiguration));
+ }
+ dispatch(addSuccessToast(t('This dashboard was saved successfully.')));
+ return response;
+ };
+
+ const onUpdateSuccess = response => {
+ const updatedDashboard = response.json.result;
+ const lastModifiedTime = response.json.last_modified_time;
+ // synching with the backend transformations of the metadata
+ if (updatedDashboard.json_metadata) {
+ const metadata = JSON.parse(updatedDashboard.json_metadata);
+ dispatch(
+ dashboardInfoChanged({
+ metadata,
+ }),
+ );
+ if (metadata.chart_configuration) {
+ dispatch({
+ type: SET_CHART_CONFIG_COMPLETE,
+ chartConfiguration: metadata.chart_configuration,
+ });
+ }
+ }
+ if (lastModifiedTime) {
+ dispatch(saveDashboardRequestSuccess(lastModifiedTime));
+ }
+ // redirect to the new slug or id
+ window.history.pushState(
+ { event: 'dashboard_properties_changed' },
+ '',
+ `/superset/dashboard/${slug || id}/`,
+ );
+
+ dispatch(addSuccessToast(t('This dashboard was saved successfully.')));
+ return response;
+ };
+
+ const onError = async response => {
+ const { error, message } = await getClientErrorObject(response);
+ let errorText = t('Sorry, an unknown error occured');
+
+ if (error) {
+ errorText = t(
+ 'Sorry, there was an error saving this dashboard: %s',
+ error,
+ );
+ }
+ if (typeof message === 'string' && message === 'Forbidden') {
+ errorText = t('You do not have permission to edit this dashboard');
+ }
+ dispatch(addDangerToast(errorText));
+ };
+
+ if (saveType === SAVE_TYPE_OVERWRITE) {
+ let chartConfiguration = {};
+ if (isFeatureEnabled(FeatureFlag.DASHBOARD_CROSS_FILTERS)) {
+ chartConfiguration = handleChartConfiguration();
+ }
+ const updatedDashboard = {
+ certified_by: cleanedData.certified_by,
+ certification_details: cleanedData.certification_details,
+ css: cleanedData.css,
+ dashboard_title: cleanedData.dashboard_title,
+ slug: cleanedData.slug,
+ owners: cleanedData.owners,
+ roles: cleanedData.roles,
+ json_metadata: safeStringify({
+ ...(cleanedData?.metadata || {}),
+ default_filters: safeStringify(serializedFilters),
+ filter_scopes: serializedFilterScopes,
+ chart_configuration: chartConfiguration,
+ }),
+ };
+
+ return SupersetClient.put({
+ endpoint: `/api/v1/dashboard/${id}`,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(updatedDashboard),
+ })
+ .then(response => onUpdateSuccess(response))
+ .catch(response => onError(response));
+ }
+ // changing the data as the endpoint requires
+ const copyData = { ...cleanedData };
+ if (copyData.metadata) {
+ delete copyData.metadata;
+ }
+ const finalCopyData = {
+ ...copyData,
+ // the endpoint is expecting the metadata to be flat
+ ...(cleanedData?.metadata || {}),
+ };
return SupersetClient.post({
endpoint: `/superset/${path}/${id}/`,
postPayload: {