-
-
-
({ value: team.id, label: team.displayName }))}
+
-
- router.push("/projects")} disabled={creatingProject}>
- Cancel
-
- {
- if (!beginPendingAction(creatingProjectRef, setCreatingProject)) {
- return;
- }
-
- return runAsynchronouslyWithAlert(async () => {
- const trimmedProjectName = projectName.trim();
- if (trimmedProjectName.length === 0) {
- throw new Error("Project name is required.");
- }
-
- const firstTeam = teams.at(0);
- const teamId = selectedTeamId ?? user.selectedTeam?.id ?? firstTeam?.id;
- if (teamId === undefined) {
- throw new Error("Select a team before creating the project.");
- }
-
- try {
- const newProject = await user.createProject({
- displayName: trimmedProjectName,
- teamId,
- onboardingStatus: "config_choice",
- });
-
- setProjectStatuses((previous) => {
- const next = new Map(previous);
- next.set(newProject.id, "config_choice");
- return next;
- });
- setProjectOnboardingStates((previous) => {
- const next = new Map(previous);
- next.set(newProject.id, null);
- return next;
- });
-
- if (redirectToNeonConfirmWith != null) {
- const confirmSearchParams = new URLSearchParams(redirectToNeonConfirmWith);
- confirmSearchParams.set("default_selected_project_id", newProject.id);
- router.push(`/integrations/neon/confirm?${confirmSearchParams.toString()}`);
- await wait(2000);
- return;
- }
-
- if (redirectToConfirmWith != null) {
- const confirmSearchParams = new URLSearchParams(redirectToConfirmWith);
- confirmSearchParams.set("default_selected_project_id", newProject.id);
- router.push(`/integrations/custom/confirm?${confirmSearchParams.toString()}`);
- await wait(2000);
- return;
- }
-
- updateSearchParams({
- project_id: newProject.id,
- mode: null,
- });
- } finally {
- endPendingAction(creatingProjectRef, setCreatingProject);
- }
- });
- }}
- >
- Create Project
-
-
+
+ router.push("/projects")} disabled={creatingProject}>
+ Cancel
+
+
+ Create Project
+
+
+
diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx
index 3fbae8abc..a586a0dc6 100644
--- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx
+++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx
@@ -1,6 +1,9 @@
// @vitest-environment jsdom
import type { ButtonHTMLAttributes, HTMLAttributes, ReactNode } from "react";
+import { readFileSync } from "fs";
+import { dirname, join } from "path";
+import { fileURLToPath } from "url";
import { afterEach, describe, expect, it, vi } from "vitest";
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
@@ -173,6 +176,19 @@ function createDeferred
() {
}
describe("ProjectOnboardingWizard", () => {
+ it("keeps the hosted auth preview interactive", () => {
+ const testDir = dirname(fileURLToPath(import.meta.url));
+ const source = readFileSync(join(testDir, "project-onboarding-wizard.tsx"), "utf-8");
+
+ const previewBlockMatch = source.match(/(<[^>]*HostedAuthMethodPreview[\s\S]*?\/>[\s\S]{0,300})/);
+ expect(previewBlockMatch).not.toBeNull();
+ const previewBlock = previewBlockMatch![1];
+
+ expect(previewBlock).not.toContain("pointer-events-none");
+ expect(previewBlock).not.toContain("inert");
+ expect(previewBlock).not.toContain("bg-transparent");
+ });
+
it("keeps required apps when normalizing persisted onboarding state", () => {
const normalizedState = normalizeProjectOnboardingState({
selected_config_choice: "create-new",
diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
index 42398e869..bd0059356 100644
--- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
+++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.tsx
@@ -823,8 +823,7 @@ export function ProjectOnboardingWizard(props: {
>
-
diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client.test.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client.test.tsx
index 2f0a955dd..e3ee335e4 100644
--- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client.test.tsx
+++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client.test.tsx
@@ -88,6 +88,21 @@ describe("new project page data loading", () => {
});
});
+describe("new project creation dialog", () => {
+ it("uses native form submission for create-project keyboard access", () => {
+ const testDir = dirname(fileURLToPath(import.meta.url));
+ const source = readFileSync(join(
+ testDir,
+ "page-client-parts/content.tsx",
+ ), "utf-8");
+
+ expect(source).toContain("