feat(embedded-sdk): Add resolvePermalinkUrl callback for custom permalink URLs (#36924)

This commit is contained in:
Michael S. Molina
2026-01-09 17:02:38 -03:00
committed by GitHub
parent 1e8d648f47
commit 53dddf4db2
9 changed files with 201 additions and 23 deletions

View File

@@ -22,6 +22,7 @@ import {
QueryFormData,
SupersetClient,
} from '@superset-ui/core';
import Switchboard from '@superset-ui/switchboard';
import rison from 'rison';
import { isEmpty } from 'lodash';
import {
@@ -31,6 +32,7 @@ import {
} from '../constants';
import { getActiveFilters } from '../dashboard/util/activeDashboardFilters';
import serializeActiveFilterValues from '../dashboard/util/serializeActiveFilterValues';
import getBootstrapData from './getBootstrapData';
export type UrlParamType = 'string' | 'number' | 'boolean' | 'object' | 'rison';
export type UrlParam = (typeof URL_PARAMS)[keyof typeof URL_PARAMS];
@@ -139,24 +141,69 @@ export function getDashboardUrlParams(
return getUrlParamEntries(urlParams);
}
function getPermalink(endpoint: string, jsonPayload: JsonObject) {
export type PermalinkResult = {
key: string;
url: string;
};
function getPermalink(
endpoint: string,
jsonPayload: JsonObject,
): Promise<PermalinkResult> {
return SupersetClient.post({
endpoint,
jsonPayload,
}).then(result => result.json.url as string);
}).then(result => ({
key: result.json.key as string,
url: result.json.url as string,
}));
}
export function getChartPermalink(
/**
* Resolves a permalink URL using the host app's custom callback if in embedded mode.
* Falls back to the default URL if not embedded or if no callback is provided.
*/
async function resolvePermalinkUrl(
result: PermalinkResult,
): Promise<PermalinkResult> {
const { key, url } = result;
// In embedded mode, check if the host app has a custom resolvePermalinkUrl callback
const bootstrapData = getBootstrapData();
if (bootstrapData.embedded) {
try {
// Ask the SDK to resolve the permalink URL
// Returns null if no callback was provided by the host
const resolvedUrl = await Switchboard.get<string | null>(
'resolvePermalinkUrl',
{ key },
);
// If callback returned a valid URL string, use it; otherwise use Superset's default URL
if (typeof resolvedUrl === 'string' && resolvedUrl.length > 0) {
return { key, url: resolvedUrl };
}
} catch (error) {
// Silently fall back to default URL if Switchboard call fails
// (e.g., if not in embedded context or callback throws)
}
}
return { key, url };
}
export async function getChartPermalink(
formData: Pick<QueryFormData, 'datasource'>,
excludedUrlParams?: string[],
) {
return getPermalink('/api/v1/explore/permalink', {
): Promise<PermalinkResult> {
const result = await getPermalink('/api/v1/explore/permalink', {
formData,
urlParams: getChartUrlParams(excludedUrlParams),
});
return resolvePermalinkUrl(result);
}
export function getDashboardPermalink({
export async function getDashboardPermalink({
dashboardId,
dataMask,
activeTabs,
@@ -186,7 +233,7 @@ export function getDashboardPermalink({
* Whether to include chart state in the permalink (default: false)
*/
includeChartState?: boolean;
}) {
}): Promise<PermalinkResult> {
const payload: JsonObject = {
urlParams: getDashboardUrlParams(),
dataMask,
@@ -199,7 +246,11 @@ export function getDashboardPermalink({
payload.chartStates = chartStates;
}
return getPermalink(`/api/v1/dashboard/${dashboardId}/permalink`, payload);
const result = await getPermalink(
`/api/v1/dashboard/${dashboardId}/permalink`,
payload,
);
return resolvePermalinkUrl(result);
}
const externalUrlRegex =