mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-26 00:53:48 +00:00
* fix(desktop): open external URL artifacts and markdown links The Web Shell relied on the webview's implicit target="_blank" / window.open handling for every external link. In the packaged desktop shell that path silently drops failed new-window requests, so link artifacts (type: link, storage: external_url) and markdown links in assistant messages appeared styled but dead, with no error feedback. Add an explicit open_external_url command to the Tauri shell (validated against http/https/mailto, opened via the OS default browser) and route external clicks through it when the Web Shell detects the desktop bridge. The artifact details panel gains an "Open link" action next to the Location URL, and failures surface as error toasts instead of silent no-ops. Plain browsers keep native anchor behavior. Fixes #9060; follows up on #8593 for the Tauri shell. * test(web-shell): keep real ToastHost exports in App mock The App test suite replaces ToastHost with a stub; after adding TOAST_REQUEST_EVENT/requestToast to the module, the partial mock broke every App test. Spread importActual so new exports stay available. * fix(desktop): declare external URL permission * fix(desktop): authorize remote external URL opens * fix(desktop): normalize external opener URLs * test(web-shell): pin desktop link click handling * fix(desktop): route modified URL clicks
49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
/**
|
|
* External-URL opening helper shared by markdown links and `external_url`
|
|
* link artifacts.
|
|
*
|
|
* Inside the packaged desktop shell, external clicks use Tauri's opener
|
|
* plugin. Plain browsers keep native anchor behavior at the call sites.
|
|
*/
|
|
|
|
type TauriInvoke = (
|
|
command: string,
|
|
args?: Record<string, unknown>,
|
|
) => Promise<unknown>;
|
|
|
|
const EXTERNAL_OPEN_SCHEMES = /^(https?:|mailto:)/i;
|
|
|
|
function tauriInvoke(): TauriInvoke | undefined {
|
|
if (typeof window === 'undefined') return undefined;
|
|
const core = (window as { __TAURI__?: { core?: { invoke?: unknown } } })
|
|
.__TAURI__?.core;
|
|
return typeof core?.invoke === 'function'
|
|
? (core.invoke as TauriInvoke)
|
|
: undefined;
|
|
}
|
|
|
|
/** True when the Web Shell runs inside the packaged Tauri desktop window. */
|
|
export function isDesktopShell(): boolean {
|
|
return tauriInvoke() !== undefined;
|
|
}
|
|
|
|
export function isExternalOpenUrl(url: string | undefined): boolean {
|
|
return Boolean(url?.trim() && EXTERNAL_OPEN_SCHEMES.test(url.trim()));
|
|
}
|
|
|
|
/**
|
|
* Opens `url` in the OS default browser. Rejects when the open fails so
|
|
* callers can surface a visible error instead of swallowing the click.
|
|
*/
|
|
export async function openExternalUrl(url: string): Promise<void> {
|
|
const invoke = tauriInvoke();
|
|
if (!invoke) throw new Error('The desktop URL opener is unavailable.');
|
|
if (!isExternalOpenUrl(url)) {
|
|
throw new Error('Only http, https, and mailto URLs can be opened.');
|
|
}
|
|
await invoke('plugin:opener|open_url', {
|
|
url: url
|
|
.trim()
|
|
.replace(EXTERNAL_OPEN_SCHEMES, (scheme) => scheme.toLowerCase()),
|
|
});
|
|
}
|