mirror of
https://github.com/runbear-io/beardrive.git
synced 2026-08-25 08:08:08 +02:00
fix(webapp): the new-project dialog no longer opens itself on arrival (BEA-80) (#129)
A signed-in account with zero projects landed on / with the create dialog already open over the onboarding page. The page renders its own "New project" button (#ob-new), so the same call to action appeared twice and the rear one was permanently pointer-intercepted — Playwright retried a click against it for 30s before failing. The auto-open was deliberate: "With no projects at all there is nothing else on the page to do." That stopped being true when the empty state gained the agent paste-prompt card — the route the docs treat as primary, which the dialog was covering. Delete the effect and its ref; fix the two comments that documented it; rewrite the e2e test that asserted the auto-open by name. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6bb7debe2b
commit
1894646093
@@ -79,20 +79,20 @@ test("join link accepts an invite after sign-in", async ({ page, browser }) => {
|
||||
await ctx.close();
|
||||
});
|
||||
|
||||
test("no projects: the create dialog opens itself, and the page behind is no dead end", async ({
|
||||
test("no projects: the onboarding page renders with no dialog, and New project opens one", async ({
|
||||
page,
|
||||
}) => {
|
||||
await login(page, "solo@example.com");
|
||||
// With nothing to browse, the one useful action opens on arrival.
|
||||
await expect(page.locator(".modal .start-points")).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.locator(".modal-input")).toHaveCount(0);
|
||||
// Nothing opens on arrival — the page's own button used to sit behind a
|
||||
// dialog nobody asked for, pointer-blocked.
|
||||
await expect(page.locator("[role=dialog]")).toHaveCount(0);
|
||||
|
||||
// Closing it leaves a page that says what to do — and a way back in.
|
||||
// The page says what to do, and the button works on the first attempt.
|
||||
await expect(page.locator(".onboard h1")).toHaveText("Welcome to BearDrive");
|
||||
await expect(page.locator(".ob-start h3")).toHaveText("Start a project");
|
||||
await page.click("#ob-new", { timeout: 2000, trial: true }); // no retry loop
|
||||
await page.click("#ob-new");
|
||||
await expect(page.locator(".modal-input")).toBeVisible();
|
||||
await expect(page.locator(".modal .start-points")).toBeVisible();
|
||||
await page.keyboard.press("Escape");
|
||||
// Dismissed once, it stays dismissed until asked for again.
|
||||
await expect(page.locator(".modal-input")).toHaveCount(0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { postJSON } from "../api/http";
|
||||
import type { InviteAccepted, Project, ProjectCreated, ServerConfig } from "../api/types";
|
||||
import { useOrgs, usePending, useProjects, useHubRefresh } from "../hooks/useHub";
|
||||
@@ -42,9 +42,11 @@ export default function HubApp({ config }: { config: ServerConfig }) {
|
||||
|
||||
const route = useMemo(() => parseRoute(loc, "hub"), [loc]);
|
||||
|
||||
// Creating a project is asked for from three places — the sidebar's +, the
|
||||
// empty state's button, and the auto-open below — so the dialog and its one
|
||||
// handler live here rather than in any of them.
|
||||
// Creating a project is asked for from two places — the sidebar's + and the
|
||||
// empty state's button — so the dialog and its one handler live here rather
|
||||
// than in either of them. It never opens on its own: it used to on arrival
|
||||
// with zero projects, which covered the empty state's agent paste-prompt
|
||||
// and pointer-blocked its own "New project" button.
|
||||
const [creating, setCreating] = useState(false);
|
||||
// A read-only hub refuses creation server-side (403), so never offer it.
|
||||
const canCreate = config.upload.enabled;
|
||||
@@ -69,17 +71,6 @@ export default function HubApp({ config }: { config: ServerConfig }) {
|
||||
}
|
||||
};
|
||||
|
||||
// With no projects at all there is nothing else on the page to do, so the
|
||||
// dialog opens itself. Once per mount, keyed off a ref rather than the
|
||||
// empty state — otherwise closing it would immediately reopen it.
|
||||
const autoOpened = useRef(false);
|
||||
useEffect(() => {
|
||||
if (autoOpened.current || joinToken) return;
|
||||
if (!projects || projects.length > 0 || !canCreate) return;
|
||||
autoOpened.current = true;
|
||||
setCreating(true);
|
||||
}, [projects, canCreate, joinToken]);
|
||||
|
||||
const newProjectDialog = creating ? (
|
||||
<NewProjectDialog
|
||||
templates={config.templates ?? []}
|
||||
|
||||
@@ -7,9 +7,9 @@ import { GuideCode, INSTALL_DOC } from "./ConnectGuide";
|
||||
// a coding agent and let it do the whole thing. The by-hand route stays a
|
||||
// docs link away.
|
||||
//
|
||||
// The create dialog also opens itself on arrival (HubApp): with no projects
|
||||
// there is nothing else on this page to do. This page is what is left when
|
||||
// someone closes it, so it must not be a dead end — hence the button.
|
||||
// This is the first thing a zero-project account sees — nothing opens over
|
||||
// it. Both cards are entry points: the button creates the project here, the
|
||||
// paste-prompt hands the whole job to an agent.
|
||||
|
||||
export function EmptyState({ onNew, canCreate }: { onNew: () => void; canCreate: boolean }) {
|
||||
return (
|
||||
|
||||
+43
-43
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BearDrive</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' fill='%23f5a623'><rect x='4' y='4' width='5.6' height='24'/><rect x='11.2' y='4' width='14.4' height='11.2'/><rect x='11.2' y='16.8' width='16.8' height='11.2'/></svg>">
|
||||
<script type="module" crossorigin src="/assets/index-wL8nzVtO.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-BiaGRL-i.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BdCy9HmN.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user