diff --git a/apps/console/app/[team]/[project]/settings/sign-ins/[signIn]/again/page.tsx b/apps/console/app/[team]/[project]/settings/sign-ins/[signIn]/again/page.tsx new file mode 100644 index 0000000..7e0c992 --- /dev/null +++ b/apps/console/app/[team]/[project]/settings/sign-ins/[signIn]/again/page.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next"; + +import { SignInAddSkeleton, SignInAgainPage } from "../../../../../../_components/sign-in-add-page"; +import { serverReadQuery } from "../../../../../../../lib/server-client"; +import { ProductPage } from "../../../../../_lib/workspace-page"; + +export const metadata: Metadata = { title: "Sign in again" }; +export default function Page({ params }: { params: Promise<{ team: string; project: string; signIn: string }> }) { + return ( + } + prefetch={(client, { projectId }) => client.prefetchQuery(serverReadQuery("projectSignIns", projectId))} + > + {({ signIn }) => } + + ); +} diff --git a/apps/console/app/[team]/[project]/settings/sign-ins/new/page.tsx b/apps/console/app/[team]/[project]/settings/sign-ins/new/page.tsx index f4a40d6..fac4fed 100644 --- a/apps/console/app/[team]/[project]/settings/sign-ins/new/page.tsx +++ b/apps/console/app/[team]/[project]/settings/sign-ins/new/page.tsx @@ -9,7 +9,7 @@ export default function Page({ params }: { params: Promise<{ team: string; proje return ( } + fallback={} prefetch={(client, { projectId }) => client.prefetchQuery(serverReadQuery("projectSignIns", projectId))} > diff --git a/apps/console/app/_components/sign-in-add-page.tsx b/apps/console/app/_components/sign-in-add-page.tsx index 40861c9..9a14765 100644 --- a/apps/console/app/_components/sign-in-add-page.tsx +++ b/apps/console/app/_components/sign-in-add-page.tsx @@ -4,18 +4,20 @@ import { useQuery } from "@tanstack/react-query"; import { ChevronLeft, TriangleAlert } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import type { BoundSignIn } from "../../lib/web-client"; import { readQuery } from "../../lib/web-client"; import { PageColumn, PageTitle, ProductGate, QueryError, useProduct } from "./shell"; import { PageSkeleton } from "./page-skeleton"; +import { PASSWORD_METHOD } from "./sign-in-methods"; import { GitHubAuthenticatorAction, GitHubAuthenticatorEditor } from "./github-authenticator"; import { SignInStageBody, useSignInStage } from "./sign-in-stage"; import type { Binding } from "./use-sign-in-binding"; /** - * Adding a way in from a product's settings, as an address of its own. + * Adding a way in from a product's settings, or signing in again to one the + * product already uses, as an address of its own. * * A route of its own rather than a modal: settings is a narrow page and the * browser wants the width, the job already has a go in, finish, @@ -56,20 +58,39 @@ function GitHubAuthenticatorOffer({ projectId, binding }: { projectId: string; b ); } -function AddStage({ bound }: { bound: readonly BoundSignIn[] }) { +/** + * Signing in again opens the way in's browser on arrival: the press that led + * here was the ask, and the page has nothing else to offer before it. + */ +function useOpenOnArrival(pick: (method: BoundSignIn["method"], signInId: string) => void, again: BoundSignIn | null) { + const asked = useRef(false); + useEffect(() => { + if (!again || asked.current) return; + asked.current = true; + pick(again.method, again.id); + }, [again, pick]); +} + +function AddStage({ bound, again, title }: { + bound: readonly BoundSignIn[]; + /** The saved way in being signed in to again; null adds a new one. */ + again: BoundSignIn | null; + title: string; +}) { const router = useRouter(); const { project, teamHref } = useProduct(); const settings = teamHref("/settings/sign-ins"); const stage = useSignInStage(project, bound); const { binding, busy } = stage; + useOpenOnArrival(stage.bind.actions.pick, again); return (