fix: link server wizard always opens inline, onboarding card grows for it

This commit is contained in:
LukeGus committed 2026-10-09 09:29:27 -05:00
1 parent 6f4198cc83
commit 83cce344e8
3 files changed
+52 -51

No files matched your search

+5 -1
View File
@@ -117,6 +117,7 @@ export function OnboardingStage({
}, [allSteps, ctx]);
const [currentId, setCurrentId] = useState<string | null>(null);
const [viewOpen, setViewOpen] = useState(false);
const lastPosition = useRef(0);
const [confirmed, setConfirmed] = useState<Set<string>>(() => new Set());
const [canContinue, setCanContinueMap] = useState<Record<string, boolean>>(
@@ -280,7 +281,10 @@ export function OnboardingStage({
<SurfaceScope
kind="tab"
className="relative flex flex-col border border-border bg-card"
onEditingChange={(editing) => setViewOpen(!!editing)}
className={`relative flex flex-col border border-border bg-card ${
viewOpen ? "min-h-[70vh]" : ""
}`}
>
<div className="flex items-center gap-2 border-b border-border px-4 py-2.5">
{Icon && <Icon size={14} className="text-muted-foreground" />}
+16 -50
View File
@@ -1,18 +1,11 @@
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { InlineView, useSurfaceKind } from "@/components/surface/surface-scope";
import { InlineView } from "@/components/surface/surface-scope";
import { toast } from "sonner";
import { AlertCircle, Loader2, X } from "lucide-react";
import { Button } from "@/components/button";
import { Input } from "@/components/input";
import { Switch } from "@/components/switch";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/components/dialog";
import { ElectronLoginForm } from "@/auth/ElectronLoginForm";
import {
completeLink,
@@ -224,7 +217,6 @@ export function LinkServerDialog({
0,
);
const wide = step === "signin";
const inSurface = useSurfaceKind() !== null;
const title = relogin
? t("sync.wizard.reloginTitle")
@@ -443,47 +435,21 @@ export function LinkServerDialog({
</>
);
// From a sidebar panel the wizard takes over the panel. Outside one (the
// first-run setup) it stays a dialog.
if (inSurface) {
return (
<InlineView
open={open}
onOpenChange={onOpenChange}
title={title}
width="wide"
scroll={!wide}
>
{!wide && (
<p className="text-xs text-muted-foreground">
{description} {step === "server" && <DocsLink core="desktopSync" />}
</p>
)}
{content}
</InlineView>
);
}
// The wizard takes over the panel, tab or onboarding step it opens from.
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent
className={`bg-card border border-border rounded-none ${
wide ? "sm:max-w-4xl h-[80vh] flex flex-col p-0 gap-0" : "sm:max-w-lg"
}`}
// The sign-in step is a page from another origin in an iframe; clicks
// inside it look like outside clicks to the dialog.
onPointerDownOutside={(event) => wide && event.preventDefault()}
onInteractOutside={(event) => wide && event.preventDefault()}
>
<DialogHeader className={wide ? "sr-only" : undefined}>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>
{description} {step === "server" && <DocsLink core="desktopSync" />}
</DialogDescription>
</DialogHeader>
{content}
</DialogContent>
</Dialog>
<InlineView
open={open}
onOpenChange={onOpenChange}
title={title}
width="wide"
scroll={!wide}
>
{!wide && (
<p className="text-xs text-muted-foreground">
{description} {step === "server" && <DocsLink core="desktopSync" />}
</p>
)}
{content}
</InlineView>
);
}
@@ -0,0 +1,31 @@
import { cleanup, render, screen } from "@testing-library/react";
import { afterEach, describe, expect, it, vi } from "vitest";
vi.mock("@/api/sync-api", () => ({
probeServer: vi.fn(),
getLinkPreview: vi.fn(),
completeLink: vi.fn(),
reloginLink: vi.fn(),
}));
vi.mock("@/auth/ElectronLoginForm", () => ({ ElectronLoginForm: () => null }));
vi.mock("sonner", () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
vi.mock("react-i18next", () => ({
useTranslation: () => ({ t: (key: string) => key }),
}));
const { SurfaceScope } = await import("@/components/surface/surface-scope");
const { LinkServerDialog } = await import("@/settings/sync/LinkServerDialog");
afterEach(cleanup);
describe("LinkServerDialog", () => {
it("opens inline in the surface instead of a popup", () => {
render(
<SurfaceScope kind="tab">
<LinkServerDialog open onOpenChange={() => {}} onLinked={() => {}} />
</SurfaceScope>,
);
expect(screen.getByText("sync.wizard.title")).toBeTruthy();
expect(screen.queryByRole("dialog")).toBeNull();
});
});