Skip to content

Commit 711bebd

Browse files
committed
refactor: manual provider configuration (#3195)
1 parent 31276a0 commit 711bebd

15 files changed

+1366
-1536
lines changed

frontend/src/app/dialogs/confirm-delete-config-frame.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default function ConfirmDeleteConfigContent({
2727
<>
2828
<Frame.Header>
2929
<Frame.Title className="gap-2 flex items-center">
30-
<div>Confirm deletion of {name}</div>
30+
<div>Confirm deletion of '{name}' provider</div>
3131
</Frame.Title>
3232
<Frame.Description>
3333
This action cannot be undone. Are you sure you want to
Lines changed: 7 additions & 234 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,12 @@
1-
import {
2-
faAws,
3-
faCheck,
4-
faServer,
5-
faSpinnerThird,
6-
Icon,
7-
} from "@rivet-gg/icons";
8-
import {
9-
useInfiniteQuery,
10-
useMutation,
11-
usePrefetchInfiniteQuery,
12-
useSuspenseInfiniteQuery,
13-
} from "@tanstack/react-query";
14-
import confetti from "canvas-confetti";
15-
import { useEffect } from "react";
16-
import { useController, useFormContext } from "react-hook-form";
17-
import z from "zod";
18-
import * as ConnectVercelForm from "@/app/forms/connect-vercel-form";
19-
import { cn, type DialogContentProps, Frame } from "@/components";
20-
import { type Region, useEngineCompatDataProvider } from "@/components/actors";
21-
import { defineStepper } from "@/components/ui/stepper";
22-
import { queryClient } from "@/queries/global";
23-
import { StepperForm } from "../forms/stepper-form";
24-
import { EnvVariablesStep } from "./connect-railway-frame";
25-
26-
const stepper = defineStepper(
27-
{
28-
id: "step-1",
29-
title: "Configure",
30-
assist: false,
31-
next: "Next",
32-
schema: z.object({
33-
runnerName: z.string().min(1, "Runner name is required"),
34-
datacenters: z
35-
.record(z.boolean())
36-
.refine(
37-
(data) => Object.values(data).some(Boolean),
38-
"At least one datacenter must be selected",
39-
),
40-
headers: z.array(z.tuple([z.string(), z.string()])).default([]),
41-
slotsPerRunner: z.coerce.number().min(1, "Must be at least 1"),
42-
maxRunners: z.coerce.number().min(1, "Must be at least 1"),
43-
minRunners: z.coerce.number().min(0, "Must be 0 or greater"),
44-
runnerMargin: z.coerce.number().min(0, "Must be 0 or greater"),
45-
}),
46-
},
47-
{
48-
id: "step-2",
49-
title: "Deploy",
50-
assist: false,
51-
schema: z.object({}),
52-
next: "Next",
53-
},
54-
{
55-
id: "step-3",
56-
title: "Confirm Connection",
57-
assist: false,
58-
schema: z.object({
59-
success: z.boolean().refine((v) => v === true, {
60-
message: "Runner must be connected to proceed",
61-
}),
62-
}),
63-
next: "Add",
64-
},
65-
);
1+
import { faAws, Icon } from "@rivet-gg/icons";
2+
import { type DialogContentProps, Frame } from "@/components";
3+
import ConnectManualServerlfullFrameContent from "./connect-manual-serverfull-frame";
664

675
interface ConnectAwsFrameContentProps extends DialogContentProps {}
686

697
export default function ConnectAwsFrameContent({
708
onClose,
719
}: ConnectAwsFrameContentProps) {
72-
usePrefetchInfiniteQuery({
73-
...useEngineCompatDataProvider().regionsQueryOptions(),
74-
pages: Infinity,
75-
});
76-
77-
const { data: datacenters } = useSuspenseInfiniteQuery(
78-
useEngineCompatDataProvider().regionsQueryOptions(),
79-
);
80-
8110
return (
8211
<>
8312
<Frame.Header>
@@ -88,167 +17,11 @@ export default function ConnectAwsFrameContent({
8817
</Frame.Title>
8918
</Frame.Header>
9019
<Frame.Content>
91-
<FormStepper onClose={onClose} datacenters={datacenters} />
20+
<ConnectManualServerlfullFrameContent
21+
provider="aws"
22+
onClose={onClose}
23+
/>
9224
</Frame.Content>
9325
</>
9426
);
9527
}
96-
97-
function FormStepper({
98-
onClose,
99-
datacenters,
100-
}: {
101-
onClose?: () => void;
102-
datacenters: Region[];
103-
}) {
104-
const provider = useEngineCompatDataProvider();
105-
const { mutateAsync } = useMutation({
106-
...provider.upsertRunnerConfigMutationOptions(),
107-
onSuccess: async () => {
108-
confetti({
109-
angle: 60,
110-
spread: 55,
111-
origin: { x: 0 },
112-
});
113-
confetti({
114-
angle: 120,
115-
spread: 55,
116-
origin: { x: 1 },
117-
});
118-
119-
await queryClient.invalidateQueries(
120-
provider.runnerConfigsQueryOptions(),
121-
);
122-
onClose?.();
123-
},
124-
});
125-
return (
126-
<StepperForm
127-
{...stepper}
128-
onSubmit={async ({ values }) => {
129-
const selectedDatacenters = Object.entries(values.datacenters)
130-
.filter(([, selected]) => selected)
131-
.map(([id]) => id);
132-
133-
const config = Object.fromEntries(
134-
selectedDatacenters.map((dc) => [
135-
dc,
136-
{
137-
normal: {},
138-
metadata: { provider: "aws" },
139-
},
140-
]),
141-
);
142-
143-
await mutateAsync({
144-
name: values.runnerName,
145-
config,
146-
});
147-
}}
148-
defaultValues={{
149-
runnerName: "default",
150-
slotsPerRunner: 25,
151-
maxRunners: 1000,
152-
runnerMargin: 0,
153-
headers: [],
154-
success: false,
155-
datacenters: Object.fromEntries(
156-
datacenters.map((dc) => [dc.id, true]),
157-
),
158-
}}
159-
content={{
160-
"step-1": () => <Step1 />,
161-
"step-2": () => <Step2 />,
162-
"step-3": () => <Step3 />,
163-
}}
164-
/>
165-
);
166-
}
167-
168-
function Step1() {
169-
return (
170-
<div className="space-y-4">
171-
<ConnectVercelForm.RunnerName />
172-
<ConnectVercelForm.Datacenters />
173-
<ConnectVercelForm.Headers />
174-
<ConnectVercelForm.SlotsPerRunner />
175-
<ConnectVercelForm.MaxRunners />
176-
<ConnectVercelForm.MinRunners />
177-
<ConnectVercelForm.RunnerMargin />
178-
</div>
179-
);
180-
}
181-
182-
function Step2() {
183-
return (
184-
<>
185-
<p>Set the following environment variables.</p>
186-
<EnvVariablesStep />
187-
</>
188-
);
189-
}
190-
191-
function Step3({ provider = "aws" }: { provider?: string }) {
192-
usePrefetchInfiniteQuery({
193-
...useEngineCompatDataProvider().runnersQueryOptions(),
194-
pages: Infinity,
195-
});
196-
197-
const { data: queryData } = useInfiniteQuery({
198-
...useEngineCompatDataProvider().runnersQueryOptions(),
199-
refetchInterval: 1000,
200-
maxPages: Infinity,
201-
});
202-
203-
const { watch } = useFormContext();
204-
205-
const datacenters: Record<string, boolean> = watch("datacenters");
206-
const chosenDatacenters = Object.entries(datacenters)
207-
.filter(([, enabled]) => enabled)
208-
.map(([dc]) => dc);
209-
210-
const runnerName: string = watch("runnerName");
211-
212-
const success = chosenDatacenters
213-
.map((dc) =>
214-
queryData?.find(
215-
(runner) =>
216-
runner.datacenter === dc && runner.name === runnerName,
217-
),
218-
)
219-
.every((v) => v);
220-
221-
const {
222-
field: { onChange },
223-
} = useController({ name: "success" });
224-
225-
useEffect(() => {
226-
onChange(success);
227-
}, [success]);
228-
229-
return (
230-
<div
231-
className={cn(
232-
"text-center h-24 text-muted-foreground text-sm overflow-hidden flex items-center justify-center",
233-
success && "text-primary-foreground",
234-
)}
235-
>
236-
{success ? (
237-
<>
238-
<Icon icon={faCheck} className="mr-1.5 text-primary" />{" "}
239-
Runner successfully connected
240-
</>
241-
) : (
242-
<div className="flex flex-col items-center gap-2">
243-
<div className="flex items-center">
244-
<Icon
245-
icon={faSpinnerThird}
246-
className="mr-1.5 animate-spin"
247-
/>{" "}
248-
Waiting for Runner to connect...
249-
</div>
250-
</div>
251-
)}
252-
</div>
253-
);
254-
}

0 commit comments

Comments
 (0)