fix(onboarding): hide the probe's diagnostics while the hire is in flight (#12902)
After a successful sign-in, a block of amber diagnostics flashed up and vanished as the step advanced. They are the identity and target INFO checks every environment test reports: they make the result a warn without blocking anything, and the step rendered any non-pass result, so they owned the screen for the window between the probe returning and setStep(5). Gated on loading rather than the connect phase. A blocking result stops the hire and handleGiveHeartbeat clears loading in the finally after its early return, so a genuine block still shows its checks while a hire in flight shows none. The button needed no change: step 4 forces the footer's loading to false and takes its label from connectCta, which reads Connecting for that whole window.
This commit is contained in:
parent
60469a08e0
commit
be407f3456
|
|
@ -2337,6 +2337,66 @@ describe("OnboardingWizard restore-gate (stale localStorage across accounts)", (
|
|||
await act(async () => root.unmount());
|
||||
});
|
||||
|
||||
it("shows no probe diagnostics between the sign-in succeeding and the step advancing", async () => {
|
||||
// Reported from staging: a block of amber diagnostics flashed up right
|
||||
// after a successful sign-in. They are the identity and target INFO
|
||||
// checks every run reports, which make the result a `warn` without
|
||||
// blocking anything — so they rendered for the window between the probe
|
||||
// returning and the step advancing, reading as an error thrown by the
|
||||
// sign-in that had just succeeded.
|
||||
mockAgentsApi.getAdapterAuthSignal.mockResolvedValue({ status: "absent" });
|
||||
mockAgentsApi.getClaudeSetupTokenLoginStatus.mockResolvedValue({
|
||||
sessionId: "claude-session-1",
|
||||
status: "authenticated",
|
||||
expiresAt: new Date(Date.now() + 600_000).toISOString(),
|
||||
});
|
||||
mockAgentsApi.testEnvironment.mockResolvedValue({
|
||||
adapterType: "claude_local",
|
||||
status: "warn",
|
||||
checks: [
|
||||
{
|
||||
code: "environment_identity",
|
||||
level: "info",
|
||||
message: 'Environment test identity for "Paperclip Computer".',
|
||||
detail: "paperclipLeaseId=ff9e58e9; provider=daytona",
|
||||
},
|
||||
],
|
||||
testedAt: new Date().toISOString(),
|
||||
});
|
||||
// Hold the hire open, which is the window the diagnostics appeared in:
|
||||
// the probe has returned but `loading` is not cleared until the `finally`
|
||||
// that runs after the step advances.
|
||||
let finishHire: (v: { agent: { id: string }; approval: null }) => void = () => {};
|
||||
mockAgentsApi.hire.mockReturnValue(
|
||||
new Promise((resolve) => {
|
||||
finishHire = resolve;
|
||||
}),
|
||||
);
|
||||
|
||||
const { root } = await openStep4({ adapterType: "claude_local" });
|
||||
await pickSource(/Claude/);
|
||||
for (let i = 0; i < 8; i++) await flushReact();
|
||||
|
||||
// Past the deliberate hold, so the hire is running and its probe is done.
|
||||
await act(async () => {
|
||||
await new Promise((resolve) => window.setTimeout(resolve, CONNECTED_HOLD_MS + 400));
|
||||
});
|
||||
for (let i = 0; i < 8; i++) await flushReact();
|
||||
|
||||
expect(mockAgentsApi.hire).toHaveBeenCalled();
|
||||
expect(document.body.textContent).not.toContain("Environment test identity");
|
||||
expect(document.body.textContent).not.toContain("Warnings");
|
||||
// And the button goes on saying what is happening rather than going quiet.
|
||||
expect(
|
||||
[...document.body.querySelectorAll("button")].pop()?.textContent?.trim(),
|
||||
).toBe("Connecting");
|
||||
|
||||
await act(async () => finishHire({ agent: { id: "agent-1" }, approval: null }));
|
||||
for (let i = 0; i < 6; i++) await flushReact();
|
||||
|
||||
await act(async () => root.unmount());
|
||||
});
|
||||
|
||||
it("starts no login when Back interrupts the collapse", async () => {
|
||||
// Backing out before the card has opened has nothing to close. Unwinding
|
||||
// through the card beat regardless mounted the panel — which starts a
|
||||
|
|
|
|||
|
|
@ -3232,7 +3232,20 @@ function OnboardingWizardInner({
|
|||
step, so this block renders only when a probe has actually
|
||||
found something: the checks the blocking error tells the
|
||||
customer to fix have to be visible somewhere. */}
|
||||
{isLocalAdapter && (adapterEnvError || (adapterEnvResult && adapterEnvResult.status !== "pass")) && (
|
||||
{/* Not while the hire is in flight. The probe's result lands
|
||||
before the hire it gates has finished, so a warn that does
|
||||
not block — the identity and target INFO checks, which
|
||||
every run reports — rendered a block of diagnostics for the
|
||||
moment between the probe returning and the step advancing.
|
||||
It read as an error thrown up by a sign-in that had just
|
||||
succeeded.
|
||||
|
||||
`loading` is the right gate rather than the connect phase:
|
||||
it is false again by the time a blocking result has stopped
|
||||
the hire, because `handleGiveHeartbeat` clears it in its
|
||||
`finally` after the early return — so a genuine block still
|
||||
shows its checks, which is the whole reason this is here. */}
|
||||
{isLocalAdapter && !loading && (adapterEnvError || (adapterEnvResult && adapterEnvResult.status !== "pass")) && (
|
||||
<div className="space-y-2 rounded-md border border-border p-3">
|
||||
{adapterEnvError && (
|
||||
<div className="rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-2 text-(length:--text-micro) text-destructive">
|
||||
|
|
|
|||
Loading…
Reference in New Issue