mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-27 21:33:41 +02:00
* fix(auth): route invitees to their workspace instead of forcing /onboarding Workspace presence now wins over `onboarded_at` across every post-auth entry point, so a user invited into an existing workspace lands inside that workspace instead of being trapped in the new-workspace wizard. The redesigned onboarding flow (#1411) intentionally flipped the priority during frontend development so every login re-entered /onboarding; the backend `onboarded_at` field shipped but the flipped priority was never restored. Closes #1837. - packages/core/paths/resolve.ts: has-workspace beats !hasOnboarded. Onboarding is reachable only when the user has zero workspaces. - apps/web/app/auth/callback/page.tsx: drop the early-return on !onboarded so a `next=/invite/<id>` survives Google OAuth round-trips. - apps/web/app/(auth)/login/page.tsx: same removal in both the already-authenticated effect and the post-login handler. - packages/views/layout/use-dashboard-guard.ts: stop bouncing in-workspace users to /onboarding; rely on the resolver for zero-workspace cases. - apps/desktop/src/renderer/src/App.tsx: window-overlay now opens onboarding only when wsCount === 0 AND !hasOnboarded. - apps/web/app/(auth)/onboarding/page.tsx: defense-in-depth — bounce away if the visitor already has a workspace, even on direct URL access. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(auth): fix URLSearchParams leaking state across callback tests The previous cleanup `mockSearchParams.forEach((_v, k) => mockSearchParams.delete(k))` silently skipped entries because forEach advances its index while the underlying URLSearchParams shrinks, so a `state=next:/invite/...` set in one test bled into the next. Snapshot keys via Array.from before deleting. Also rewrites the assertions to match the new policy: an unonboarded user with a safe `next=` honors it, with a workspace lands in that workspace, and only with zero workspaces falls back to /onboarding. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
43 lines
1.2 KiB
TypeScript
43 lines
1.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { Workspace } from "../types";
|
|
import { paths } from "./paths";
|
|
import { resolvePostAuthDestination } from "./resolve";
|
|
|
|
function makeWs(slug: string): Workspace {
|
|
return {
|
|
id: `id-${slug}`,
|
|
name: slug,
|
|
slug,
|
|
description: null,
|
|
context: null,
|
|
settings: {},
|
|
repos: [],
|
|
issue_prefix: slug.toUpperCase(),
|
|
created_at: "",
|
|
updated_at: "",
|
|
};
|
|
}
|
|
|
|
describe("resolvePostAuthDestination", () => {
|
|
it("has workspace → /<first.slug>/issues regardless of onboarded state", () => {
|
|
const ws = [makeWs("acme"), makeWs("beta")];
|
|
expect(resolvePostAuthDestination(ws, true)).toBe(
|
|
paths.workspace("acme").issues(),
|
|
);
|
|
expect(resolvePostAuthDestination(ws, false)).toBe(
|
|
paths.workspace("acme").issues(),
|
|
);
|
|
expect(resolvePostAuthDestination([makeWs("acme")], false)).toBe(
|
|
paths.workspace("acme").issues(),
|
|
);
|
|
});
|
|
|
|
it("zero workspaces + !onboarded → /onboarding", () => {
|
|
expect(resolvePostAuthDestination([], false)).toBe(paths.onboarding());
|
|
});
|
|
|
|
it("zero workspaces + onboarded → /workspaces/new", () => {
|
|
expect(resolvePostAuthDestination([], true)).toBe(paths.newWorkspace());
|
|
});
|
|
});
|