fix(gui): keep app landings through signup, and unstack the session picker

Signing up from a direct /app/<name> landing redirected to '/' on
success, silently dropping the app the URL asked for — the deep link's
launch (and its dashboard intro) never happened. Signup now mirrors
login's pathname-preserving redirect, but only for app-landing routes
(/app/<name>, /desktop/app/<name>): every other route keeps the
historical '/', notably /action/signup, where returning to the same
path would just show the signup form again. The query string stays
dropped, matching login's credential-leak hygiene. This covers all
three signup entry points reachable from a landing: the login cover's
"Sign up", the session picker's "Create Account", and the
must_login_or_signup fallback.

The session picker (UIWindowSessionList) also left itself on top of
the cover windows its two links open, hiding their username fields:
"Create Account" tried to close the picker via the LOGIN window's
c2a selector (which matches nothing in the picker), and "Log Into
Another Account" never closed it at all. Both now close the picker —
in the reload flows only: the no-reload (popup) flows keep it open,
where it doubles as the fallback UI when the login/signup window is
abandoned mid-flow.

Picking an account was already correct (location.reload() keeps the
landing URL); with these fixes all three picker paths, plain login,
and signup all return to the app landing, where the boot replays the
launch and its intro.
This commit is contained in:
jelveh
2026-08-07 11:51:44 -07:00
parent 5538a5d24b
commit 085ac116c7
2 changed files with 35 additions and 2 deletions
+12 -1
View File
@@ -97,6 +97,13 @@ async function UIWindowSessionList (options) {
},
});
$(el_window).find('.login-c2a-session-list').on('click', async function (e) {
// The login window is a centered cover and this picker would
// otherwise float on top of it, hiding its username field. Only
// the reload flows close it: in the no-reload (popup) flows the
// picker doubles as the fallback UI when the login window is
// abandoned, and the resolve() below still needs a live promise
// chain either way.
if ( options.reload_on_success ) $(el_window).close();
const login = await UIWindowLogin({
referrer: options.referrer,
reload_on_success: options.reload_on_success,
@@ -120,7 +127,11 @@ async function UIWindowSessionList (options) {
}
});
$(el_window).find('.signup-c2a-session-list').on('click', async function (e) {
$('.signup-c2a-clickable').parents('.window').close();
// Same picker-over-cover overlap as the login c2a above, same
// reload-flows-only close. (The selector this replaces —
// '.signup-c2a-clickable', the LOGIN window's c2a class —
// matched nothing in this window and closed nothing.)
if ( options.reload_on_success ) $(el_window).close();
// create Signup window
const signup = await UIWindowSignup({
referrer: options.referrer,
+23 -1
View File
@@ -574,7 +574,29 @@ function UIWindowSignup(options) {
if (options.reload_on_success) {
window.onbeforeunload = null;
const redirectUrl = options.redirect_url || '/';
// Signup can interrupt a direct app landing (the
// login cover page's "Sign up", the session
// picker's "Create Account", the
// must_login_or_signup fallback) — landing on '/'
// afterwards would silently drop the app the URL
// asked for, so app landings are preserved and
// the reloaded boot replays them, launch and
// dashboard intro included (the query string is
// deliberately left behind, mirroring login's
// credential-leak hygiene). Every other route
// keeps the historical '/' — notably
// /action/signup, where coming back to the same
// path would just show this window again.
const on_app_landing =
/^\/(?:desktop\/)?app\/[^/]+\/?$/.test(
window.location.pathname,
);
const redirectUrl =
options.redirect_url ||
(on_app_landing
? window.location.origin +
window.location.pathname
: '/');
window.location.replace(redirectUrl);
} else {
resolve(email_verified);