Skip to content

Commit 861687a

Browse files
committed
feat(vercel): implement build settings fields for Vercel integration
Add a new component, BuildSettingsFields, to manage Vercel build settings, including options for pulling environment variables before builds, discovering new environment variables, and enabling atomic deployments. Update related routes and schemas to accommodate the new discoverEnvVars functionality, replacing the previous pullNewEnvVars option. This enhances the Vercel integration by providing a more granular control over environment variable management during builds.
1 parent 7b9acb6 commit 861687a

File tree

5 files changed

+317
-234
lines changed

5 files changed

+317
-234
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import { Switch } from "~/components/primitives/Switch";
2+
import { Label } from "~/components/primitives/Label";
3+
import { Hint } from "~/components/primitives/Hint";
4+
import { TextLink } from "~/components/primitives/TextLink";
5+
import {
6+
EnvironmentIcon,
7+
environmentFullTitle,
8+
environmentTextClassName,
9+
} from "~/components/environments/EnvironmentLabel";
10+
import type { EnvSlug } from "~/v3/vercel/vercelProjectIntegrationSchema";
11+
12+
type BuildSettingsFieldsProps = {
13+
availableEnvSlugs: EnvSlug[];
14+
pullEnvVarsBeforeBuild: EnvSlug[];
15+
onPullEnvVarsChange: (slugs: EnvSlug[]) => void;
16+
discoverEnvVars: EnvSlug[];
17+
onDiscoverEnvVarsChange: (slugs: EnvSlug[]) => void;
18+
atomicBuilds: EnvSlug[];
19+
onAtomicBuildsChange: (slugs: EnvSlug[]) => void;
20+
envVarsConfigLink?: string;
21+
};
22+
23+
function slugToEnvType(slug: EnvSlug) {
24+
return slug === "prod" ? "PRODUCTION" : slug === "stg" ? "STAGING" : "PREVIEW";
25+
}
26+
27+
export function BuildSettingsFields({
28+
availableEnvSlugs,
29+
pullEnvVarsBeforeBuild,
30+
onPullEnvVarsChange,
31+
discoverEnvVars,
32+
onDiscoverEnvVarsChange,
33+
atomicBuilds,
34+
onAtomicBuildsChange,
35+
envVarsConfigLink,
36+
}: BuildSettingsFieldsProps) {
37+
return (
38+
<>
39+
{/* Pull env vars before build */}
40+
<div>
41+
<div className="mb-2 flex items-center justify-between">
42+
<div>
43+
<Label>Pull env vars before build</Label>
44+
<Hint>
45+
Select which environments should pull environment variables from Vercel before each
46+
build.{" "}
47+
{envVarsConfigLink && (
48+
<>
49+
<TextLink to={envVarsConfigLink}>Configure which variables to pull</TextLink>.
50+
</>
51+
)}
52+
</Hint>
53+
</div>
54+
{availableEnvSlugs.length > 1 && (
55+
<Switch
56+
variant="small"
57+
checked={
58+
availableEnvSlugs.length > 0 &&
59+
availableEnvSlugs.every((s) => pullEnvVarsBeforeBuild.includes(s))
60+
}
61+
onCheckedChange={(checked) => {
62+
onPullEnvVarsChange(checked ? [...availableEnvSlugs] : []);
63+
}}
64+
/>
65+
)}
66+
</div>
67+
<div className="flex flex-col gap-2 rounded border bg-charcoal-800 p-3">
68+
{availableEnvSlugs.map((slug) => {
69+
const envType = slugToEnvType(slug);
70+
return (
71+
<div key={slug} className="flex items-center justify-between">
72+
<div className="flex items-center gap-1.5">
73+
<EnvironmentIcon environment={{ type: envType }} className="size-4" />
74+
<span className={`text-sm ${environmentTextClassName({ type: envType })}`}>
75+
{environmentFullTitle({ type: envType })}
76+
</span>
77+
</div>
78+
<Switch
79+
variant="small"
80+
checked={pullEnvVarsBeforeBuild.includes(slug)}
81+
onCheckedChange={(checked) => {
82+
onPullEnvVarsChange(
83+
checked
84+
? [...pullEnvVarsBeforeBuild, slug]
85+
: pullEnvVarsBeforeBuild.filter((s) => s !== slug)
86+
);
87+
}}
88+
/>
89+
</div>
90+
);
91+
})}
92+
</div>
93+
</div>
94+
95+
{/* Discover new env vars */}
96+
<div>
97+
<div className="mb-2 flex items-center justify-between">
98+
<div>
99+
<Label>Discover new env vars</Label>
100+
<Hint>
101+
Select which environments should automatically discover and create new environment
102+
variables from Vercel during builds.
103+
</Hint>
104+
</div>
105+
{availableEnvSlugs.length > 1 && (
106+
<Switch
107+
variant="small"
108+
checked={
109+
availableEnvSlugs.length > 0 &&
110+
availableEnvSlugs.every(
111+
(s) => discoverEnvVars.includes(s) || !pullEnvVarsBeforeBuild.includes(s)
112+
) &&
113+
availableEnvSlugs.some((s) => discoverEnvVars.includes(s))
114+
}
115+
disabled={!availableEnvSlugs.some((s) => pullEnvVarsBeforeBuild.includes(s))}
116+
onCheckedChange={(checked) => {
117+
onDiscoverEnvVarsChange(
118+
checked
119+
? availableEnvSlugs.filter((s) => pullEnvVarsBeforeBuild.includes(s))
120+
: []
121+
);
122+
}}
123+
/>
124+
)}
125+
</div>
126+
<div className="flex flex-col gap-2 rounded border bg-charcoal-800 p-3">
127+
{availableEnvSlugs.map((slug) => {
128+
const envType = slugToEnvType(slug);
129+
const isPullDisabled = !pullEnvVarsBeforeBuild.includes(slug);
130+
return (
131+
<div
132+
key={slug}
133+
className={`flex items-center justify-between ${isPullDisabled ? "opacity-50" : ""}`}
134+
>
135+
<div className="flex items-center gap-1.5">
136+
<EnvironmentIcon environment={{ type: envType }} className="size-4" />
137+
<span className={`text-sm ${environmentTextClassName({ type: envType })}`}>
138+
{environmentFullTitle({ type: envType })}
139+
</span>
140+
</div>
141+
<Switch
142+
variant="small"
143+
checked={discoverEnvVars.includes(slug)}
144+
disabled={isPullDisabled}
145+
onCheckedChange={(checked) => {
146+
onDiscoverEnvVarsChange(
147+
checked
148+
? [...discoverEnvVars, slug]
149+
: discoverEnvVars.filter((s) => s !== slug)
150+
);
151+
}}
152+
/>
153+
</div>
154+
);
155+
})}
156+
</div>
157+
</div>
158+
159+
{/* Atomic deployments */}
160+
<div>
161+
<div className="flex items-center justify-between">
162+
<div>
163+
<Label>Atomic deployments</Label>
164+
<Hint>
165+
When enabled, production deployments wait for Vercel deployment to complete before
166+
promoting the Trigger.dev deployment.
167+
</Hint>
168+
</div>
169+
<Switch
170+
variant="small"
171+
checked={atomicBuilds.includes("prod")}
172+
onCheckedChange={(checked) => {
173+
onAtomicBuildsChange(checked ? ["prod"] : []);
174+
}}
175+
/>
176+
</div>
177+
</div>
178+
</>
179+
);
180+
}

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,23 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
187187
return json(submission);
188188
}
189189

190+
// Clean up syncEnvVarsMapping if Vercel integration exists
191+
const vercelService = new VercelIntegrationService();
192+
const integration = await vercelService.getVercelProjectIntegration(project.id);
193+
if (integration) {
194+
const runtimeEnv = await prisma.runtimeEnvironment.findUnique({
195+
where: { id: submission.value.environmentId },
196+
select: { type: true },
197+
});
198+
if (runtimeEnv) {
199+
await vercelService.removeSyncEnvVarForEnvironment(
200+
project.id,
201+
submission.value.key,
202+
runtimeEnv.type as TriggerEnvironmentType
203+
);
204+
}
205+
}
206+
190207
return redirectWithSuccessMessage(
191208
v3EnvironmentVariablesPath(
192209
{ slug: organizationSlug },

0 commit comments

Comments
 (0)