diff --git a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte index e24a280d87..765d1ceffe 100644 --- a/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte +++ b/frontend/src/lib/components/apps/editor/AppEditorHeader.svelte @@ -757,6 +757,7 @@ {/snippet} void @@ -57,6 +58,11 @@ // document and break no-CORP cross-origin subresources (external images, // {@html} embeds, CDN imports). rawApp?: boolean + /** True while the editor is on a draft-only URL (`/edit/u/{user}/draft_{uuid}` + * with no deployed row yet). Suppresses the public-secret-URL fetch + * (`/secret_of/...` 404s with no `app` row) and renders a placeholder + * instead of the eternally-spinning link. */ + newApp?: boolean } = $props() let isDeployer = $derived($userStore?.groups?.includes(WM_DEPLOYERS_GROUP) ?? false) @@ -139,7 +145,15 @@ }) $effect(() => { - appPath && appPath != '' && savedApp && secretUrl == undefined && untrack(() => getSecretUrl()) + // Skip the secret URL fetch on draft-only items — `/secret_of/...` + // has no `app` row to look up and would 404, leaving the UI + // component spinning indefinitely. + !newApp && + appPath && + appPath != '' && + savedApp && + secretUrl == undefined && + untrack(() => getSecretUrl()) }) @@ -267,8 +281,8 @@ disabled={!savedApp} /> - {#if !savedApp} - + {#if !savedApp || newApp} + {:else if secretUrlHref}