Skip to content
Closed
2 changes: 1 addition & 1 deletion frontend/src/app/connect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function Connect({
<div className="flex-1 flex flex-col gap-2 mt-4">
<div className="flex flex-row justify-stretch items-center gap-2">
<DocsSheet
path={docsLinks.gettingStarted.node}
path={docsLinks.gettingStarted.js}
title="Node.js & Bun Quickstart"
>
<Button
Expand Down
14 changes: 12 additions & 2 deletions frontend/src/app/data-providers/engine-data-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,12 @@ export const createNamespaceContext = ({
variant?: Rivet.RunnerConfigVariant;
}) {
return infiniteQueryOptions({
queryKey: [{ namespace }, "runners", "configs", opts],
queryKey: [
{ namespace },
"runners",
"configs",
{ variant: opts?.variant },
],
initialPageParam: undefined as string | undefined,
queryFn: async ({ signal: abortSignal, pageParam }) => {
const response = await client.runnerConfigs.list(
Expand Down Expand Up @@ -621,7 +626,12 @@ export const createNamespaceContext = ({
variant?: Rivet.RunnerConfigVariant;
}) {
return queryOptions({
queryKey: [{ namespace }, "runners", "config", opts],
queryKey: [
{ namespace },
"runners",
"config",
{ name: opts.name, variant: opts.variant },
],
enabled: !!opts.name,
queryFn: async ({ signal: abortSignal }) => {
const response = await client.runnerConfigs.list(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,8 +185,8 @@ export function EnvVariablesStep() {
<p>Value</p>
</Label>
<RivetEndpointEnv />
<RivetTokenEnv />
<RivetNamespaceEnv />
<RivetTokenEnv />
<RivetRunnerEnv />
</div>
<div className="mt-2 flex justify-end">
Expand Down
8 changes: 5 additions & 3 deletions frontend/src/app/dialogs/connect-manual-serverless-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ function FormStepper({
let existing: Record<string, Rivet.RunnerConfig> = {};
try {
const runnerConfig = await queryClient.fetchQuery(
provider.runnerConfigQueryOptions({name: values.runnerName}),
provider.runnerConfigQueryOptions({
name: values.runnerName,
}),
);
existing = runnerConfig?.datacenters || {};
} catch {
Expand Down Expand Up @@ -158,8 +160,8 @@ function FormStepper({
}}
defaultValues={{
runnerName: "default",
slotsPerRunner: 25,
maxRunners: 1000,
slotsPerRunner: 1,
maxRunners: 10000,
minRunners: 1,
runnerMargin: 0,
headers: [],
Expand Down
186 changes: 186 additions & 0 deletions frontend/src/app/dialogs/connect-quick-railway-frame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import { faRailway, Icon } from "@rivet-gg/icons";
import {
useMutation,
usePrefetchInfiniteQuery,
useSuspenseInfiniteQuery,
} from "@tanstack/react-query";
import confetti from "canvas-confetti";
import z from "zod";
import * as ConnectRailwayForm from "@/app/forms/connect-railway-form";
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
type DialogContentProps,
ExternalLinkCard,
Frame,
} from "@/components";
import { useEngineCompatDataProvider } from "@/components/actors";
import { defineStepper } from "@/components/ui/stepper";
import { queryClient } from "@/queries/global";
import { useRailwayTemplateLink } from "@/utils/use-railway-template-link";
import { StepperForm } from "../forms/stepper-form";

const stepper = defineStepper(
{
id: "step-1",
title: "Deploy to Railway",
assist: false,
next: "Next",
schema: z.object({
runnerName: z.string().min(1, "Runner name is required"),
datacenter: z.string().min(1, "Please select a region"),
}),
},
{
id: "step-2",
title: "Wait for the Runner to connect",
assist: true,
schema: z.object({
success: z.boolean().refine((v) => v === true, {
message: "Runner must be connected to proceed",
}),
}),
next: "Add",
},
);

interface ConnectQuickRailwayFrameContentProps extends DialogContentProps {}

export default function ConnectQuickRailwayFrameContent({
onClose,
}: ConnectQuickRailwayFrameContentProps) {
usePrefetchInfiniteQuery({
...useEngineCompatDataProvider().regionsQueryOptions(),
pages: Infinity,
});
const { data } = useSuspenseInfiniteQuery(
useEngineCompatDataProvider().regionsQueryOptions(),
);

const prefferedRegionForRailway =
data.find((region) => region.name.toLowerCase().includes("us-west"))
?.id ||
data.find((region) => region.name.toLowerCase().includes("us-east"))
?.id ||
data.find((region) => region.name.toLowerCase().includes("ore"))?.id ||
"auto";

return (
<>
<Frame.Header>
<Frame.Title className="gap-2 flex items-center">
<div>
Add <Icon icon={faRailway} className="ml-0.5" /> Railway
</div>
</Frame.Title>
</Frame.Header>
<Frame.Content>
<FormStepper
onClose={onClose}
defaultDatacenter={prefferedRegionForRailway}
/>
</Frame.Content>
</>
);
}

function FormStepper({
onClose,
defaultDatacenter,
}: {
onClose?: () => void;
defaultDatacenter: string;
}) {
const provider = useEngineCompatDataProvider();
const { mutateAsync } = useMutation({
...provider.upsertRunnerConfigMutationOptions(),
onSuccess: async () => {
confetti({
angle: 60,
spread: 55,
origin: { x: 0 },
});
confetti({
angle: 120,
spread: 55,
origin: { x: 1 },
});

await queryClient.invalidateQueries(
provider.runnerConfigsQueryOptions(),
);
onClose?.();
},
});
return (
<StepperForm
{...stepper}
onSubmit={async ({ values }) => {
await mutateAsync({
name: values.runnerName,
config: {
[values.datacenter]: {
normal: {},
metadata: { provider: "railway" },
},
},
});
}}
defaultValues={{
runnerName: "default",
success: true,
datacenter: defaultDatacenter,
}}
content={{
"step-1": () => <Step1 datacenter={defaultDatacenter} />,
"step-2": () => <Step2 />,
}}
/>
);
}

function Step1({ datacenter }: { datacenter: string }) {
return (
<>
<div className="space-y-4">
<p>
Deploy the Rivet Railway template to get started quickly.
</p>
<DeployToRailwayButton datacenter={datacenter} />
</div>
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger className="text-sm">
Advanced Options
</AccordionTrigger>
<AccordionContent className="space-y-4 px-1 pt-2">
<ConnectRailwayForm.RunnerName />
<ConnectRailwayForm.Datacenter />
</AccordionContent>
</AccordionItem>
</Accordion>
</>
);
}

function DeployToRailwayButton({ datacenter }: { datacenter: string }) {
const runnerName = "default";
const url = useRailwayTemplateLink({
runnerName,
datacenter,
});

return (
<ExternalLinkCard
href={url}
icon={faRailway}
title="Deploy Template to Railway"
/>
);
}

function Step2() {
return <ConnectRailwayForm.ConnectionCheck provider="railway" />;
}
87 changes: 38 additions & 49 deletions frontend/src/app/dialogs/connect-quick-vercel-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import {
AccordionItem,
AccordionTrigger,
type DialogContentProps,
ExternalLinkCard,
Frame,
} from "@/components";
import { type Region, useEngineCompatDataProvider } from "@/components/actors";
import { queryClient } from "@/queries/global";
import { StepperForm } from "../forms/stepper-form";
import { VERCEL_SERVERLESS_MAX_DURATION } from "./connect-vercel-frame";
import { EnvVariablesStep } from "./connect-railway-frame";

const { stepper } = ConnectVercelForm;
Expand Down Expand Up @@ -84,7 +86,6 @@ function FormStepper({
{...stepper}
content={{
"initial-info": () => <StepInitialInfo />,
"env-vars": () => <StepEnvVars />,
deploy: () => <StepDeploy />,
}}
onSubmit={async ({ values }) => {
Expand All @@ -98,10 +99,7 @@ function FormStepper({
maxRunners: values.maxRunners,
slotsPerRunner: values.slotsPerRunner,
runnersMargin: values.runnerMargin,
requestLifespan:
ConnectVercelForm.PLAN_TO_MAX_DURATION[
values.plan
] - 5, // Subtract 5s to ensure we don't hit Vercel's timeout
requestLifespan: VERCEL_SERVERLESS_MAX_DURATION - 5, // Subtract 5s to ensure we don't hit Vercel's timeout
headers: Object.fromEntries(
values.headers.map(([key, value]) => [key, value]),
),
Expand All @@ -121,11 +119,10 @@ function FormStepper({
});
}}
defaultValues={{
plan: "hobby",
runnerName: "default",
slotsPerRunner: 25,
slotsPerRunner: 1,
minRunners: 1,
maxRunners: 1000,
maxRunners: 10_000,
runnerMargin: 0,
headers: [],
success: false,
Expand All @@ -140,57 +137,49 @@ function FormStepper({
function StepInitialInfo() {
return (
<>
<ConnectVercelForm.Plan />
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger className="text-sm">
Advanced options
</AccordionTrigger>
<AccordionContent className="space-y-4 px-1 pt-2">
<ConnectVercelForm.RunnerName />
<ConnectVercelForm.Datacenters />
<ConnectVercelForm.Headers />
<ConnectVercelForm.SlotsPerRunner />
<ConnectVercelForm.MinRunners />
<ConnectVercelForm.MaxRunners />
<ConnectVercelForm.RunnerMargin />
</AccordionContent>
</AccordionItem>
</Accordion>
</>
);
}

function StepEnvVars() {
return (
<>
<p>
Set the following environment variables in your Vercel project
settings.
</p>
<EnvVariablesStep />
<div className="space-y-4">
<p>
Deploy the Rivet Vercel template to get started quickly.
</p>
<ExternalLinkCard
href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Frivet-dev%2Ftemplate-vercel&env=NEXT_PUBLIC_RIVET_ENDPOINT,NEXT_PUBLIC_RIVET_TOKEN,NEXT_PUBLIC_RIVET_NAMESPACE&project-name=rivetkit-vercel&repository-name=rivetkit-vercel"
icon={faVercel}
title="Deploy Template to Vercel"
/>
</div>
<div className="space-y-4">
<p>
Set the following environment variables:
</p>
<EnvVariablesStep />
</div>
</>
);
}

function StepDeploy() {
return (
<>
<p>
<a
href="https://vercel.com/docs/deployments"
target="_blank"
rel="noreferrer"
className=" underline"
>
Deploy your project to Vercel using your preferred method
</a>
. After deployment, return here to add the endpoint.
</p>
<div className="mt-2">
<ConnectVercelForm.Endpoint />
<ConnectVercelForm.ConnectionCheck provider="Vercel" />
<Accordion type="single" collapsible>
<AccordionItem value="item-1">
<AccordionTrigger className="text-sm">
Advanced
</AccordionTrigger>
<AccordionContent className="space-y-4 px-1 pt-2">
<ConnectVercelForm.RunnerName />
<ConnectVercelForm.Datacenters />
<ConnectVercelForm.Headers />
<ConnectVercelForm.SlotsPerRunner />
<ConnectVercelForm.MinRunners />
<ConnectVercelForm.MaxRunners />
<ConnectVercelForm.RunnerMargin />
</AccordionContent>
</AccordionItem>
</Accordion>
</div>
<ConnectVercelForm.ConnectionCheck provider="Vercel" />
</>
);
}
Loading
Loading