Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions frontend/src/app/data-providers/cloud-data-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export const createOrganizationContext = ({
};

return {
organization,
orgProjectNamespacesQueryOptions,
currentOrgProjectNamespacesQueryOptions: (opts: {
project: string;
Expand Down Expand Up @@ -233,6 +234,7 @@ export const createProjectContext = ({
} & ReturnType<typeof createOrganizationContext> &
ReturnType<typeof createGlobalContext>) => {
return {
project,
createNamespaceMutationOptions(opts: {
onSuccess?: (data: Namespace) => void;
}) {
Expand Down Expand Up @@ -355,5 +357,29 @@ export const createNamespaceContext = ({
namespaceQueryOptions() {
return parent.currentProjectNamespaceQueryOptions({ namespace });
},
connectRunnerTokenQueryOptions() {
return queryOptions({
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 5 * 60 * 1000, // 5 minutes
queryKey: [
{
namespace,
project: parent.project,
organization: parent.organization,
},
"runners",
"connect",
],
queryFn: async () => {
const f = parent.client.namespaces.createPublishableToken(
parent.project,
namespace,
{ org: parent.organization },
);
const t = await f;
return t.token;
},
});
},
};
};
14 changes: 14 additions & 0 deletions frontend/src/app/data-providers/engine-data-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type Rivet, RivetClient } from "@rivetkit/engine-api-full";
import { infiniteQueryOptions, queryOptions } from "@tanstack/react-query";
import { getConfig, ls } from "@/components";
import {
type Actor,
ActorFeature,
Expand Down Expand Up @@ -551,6 +552,19 @@ export const createNamespaceContext = ({
},
});
},
connectRunnerTokenQueryOptions() {
return queryOptions({
staleTime: 1000,
gcTime: 1000,
queryKey: [{ namespace }, "runners", "connect"],
queryFn: async () => {
return ls.engineCredentials.get(getConfig().apiUrl) || "";
},
meta: {
mightRequireAuth,
},
});
},
};
};

Expand Down
167 changes: 159 additions & 8 deletions frontend/src/app/dialogs/connect-railway-frame.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import { faQuestionCircle, faRailway, Icon } from "@rivet-gg/icons";
import { useQuery } from "@tanstack/react-query";
import * as ConnectRailwayForm from "@/app/forms/connect-railway-form";
import { HelpDropdown } from "@/app/help-dropdown";
import { Button, Flex, Frame } from "@/components";
import {
Button,
type DialogContentProps,
DiscreteInput,
Frame,
Skeleton,
} from "@/components";
import { useEngineCompatDataProvider } from "@/components/actors";
import { defineStepper } from "@/components/ui/stepper";
import { engineEnv } from "@/lib/env";

export default function CreateProjectFrameContent() {
const { Stepper } = defineStepper(
{
id: "step-1",
title: "Deploy to Railway",
},
{
id: "step-2",
title: "Set Environment Variables",
},
{
id: "step-3",
title: "Confirm Connection",
},
);

interface ConnectRailwayFrameContentProps extends DialogContentProps {}

export default function ConnectRailwayFrameContent({
onClose,
}: ConnectRailwayFrameContentProps) {
return (
<ConnectRailwayForm.Form
onSubmit={async () => {}}
defaultValues={{ name: "" }}
defaultValues={{ endpoint: "" }}
>
<Frame.Header>
<Frame.Title className="justify-between flex items-center">
Expand All @@ -22,12 +51,134 @@ export default function CreateProjectFrameContent() {
</Frame.Title>
</Frame.Header>
<Frame.Content>
<Flex gap="4" direction="col">
<ConnectRailwayForm.Name />
<ConnectRailwayForm.Preview />
<ConnectRailwayForm.ConnectionCheck />
</Flex>
<FormStepper onClose={onClose} />
</Frame.Content>
</ConnectRailwayForm.Form>
);
}

function FormStepper({ onClose }: { onClose?: () => void }) {
return (
<Stepper.Provider variant="vertical">
{({ methods }) => (
<>
<Stepper.Navigation>
{methods.all.map((step) => (
<Stepper.Step
key={step.id}
className="min-w-0"
of={step.id}
onClick={() => methods.goTo(step.id)}
>
<Stepper.Title>{step.title}</Stepper.Title>
{methods.when(step.id, (step) => {
return (
<Stepper.Panel className="space-y-4">
{step.id === "step-1" && (
<>
<p>
Deploy any RivetKit app
to Railway.
</p>
<p>
Or use our Railway
template to get started
quickly.
</p>
<a
href="https://railway.com/deploy/rivet?referralCode=RC7bza&utm_medium=integration&utm_source=template&utm_campaign=generic"
target="_blank"
rel="noreferrer"
className="inline-block h-10"
>
<img
height={40}
src="https://railway.com/button.svg"
alt="Deploy to Railway"
/>
</a>

<p>
After deploying your app
to Railway, return here
to add the endpoint.
</p>
</>
)}
{step.id === "step-2" && (
<EnvVariablesStep />
)}
{step.id === "step-3" && (
<div>
<ConnectRailwayForm.Endpoint
placeholder="https://your-application.up.railway.app/"
className="mb-2"
/>
<ConnectRailwayForm.ConnectionCheck />
</div>
)}
<Stepper.Controls>
<Button
type="button"
variant="secondary"
onClick={methods.prev}
disabled={methods.isFirst}
>
Previous
</Button>
<Button
onClick={
methods.isLast
? onClose
: methods.next
}
>
{methods.isLast
? "Done"
: "Next"}
</Button>
</Stepper.Controls>
</Stepper.Panel>
);
})}
</Stepper.Step>
))}
</Stepper.Navigation>
</>
)}
</Stepper.Provider>
);
}

function EnvVariablesStep() {
const dataProvider = useEngineCompatDataProvider();

const { data, isLoading } = useQuery(
dataProvider.connectRunnerTokenQueryOptions(),
);

return (
<>
<p>
Set the following environment variables in your Railway project
settings.
</p>
<div className="gap-1 items-center">
{__APP_TYPE__ === "engine" ? (
<div className="flex gap-1 items-center border-b border-b-border/40 pb-2 mb-2">
<DiscreteInput value="RIVET_ENGINE" show />
<DiscreteInput value={engineEnv().VITE_APP_API_URL} />
</div>
) : null}
<div className="flex gap-1 items-center">
<DiscreteInput value="RIVET_TOKEN" show />
{isLoading ? (
<Skeleton className="w-56 h-10" />
) : (
<DiscreteInput value={data || ""} />
)}
</div>
</div>
</>
);
}
6 changes: 2 additions & 4 deletions frontend/src/app/dialogs/connect-vercel-frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
Button,
type DialogContentProps,
Frame,
Step,
Steps,
} from "@/components";
import { defineStepper } from "@/components/ui/stepper";

Expand All @@ -25,7 +23,7 @@ const { Stepper } = defineStepper(
},
{
id: "step-4",
title: "Add Vercel Endpoint",
title: "Confirm Connection",
},
);

Expand Down Expand Up @@ -69,7 +67,7 @@ function FormStepper({ onClose }: { onClose?: () => void }) {
<Stepper.Navigation>
{methods.all.map((step) => (
<Stepper.Step
className="min-w-0"
className="min-w-0"
of={step.id}
onClick={() => methods.goTo(step.id)}
>
Expand Down
Loading
Loading