Skip to content

Commit 20e97fc

Browse files
committed
feat(webapp): write default region to the environment
SetDefaultRegionService now sets RuntimeEnvironment.defaultWorkerGroupId (allowlist checks stay project-scoped). Regions route resolves the env in its loader and action.
1 parent f834ace commit 20e97fc

2 files changed

Lines changed: 34 additions & 16 deletions

File tree

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

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,26 +52,37 @@ import { useOrganization } from "~/hooks/useOrganizations";
5252
import { useHasAdminAccess } from "~/hooks/useUser";
5353
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
5454
import { findProjectBySlug } from "~/models/project.server";
55+
import { findEnvironmentBySlug } from "~/models/runtimeEnvironment.server";
5556
import { type Region, RegionsPresenter } from "~/presenters/v3/RegionsPresenter.server";
5657
import { requireUser } from "~/services/session.server";
5758
import {
5859
docsPath,
5960
EnvironmentParamSchema,
60-
ProjectParamSchema,
6161
regionsPath,
6262
v3BillingPath,
6363
} from "~/utils/pathBuilder";
6464
import { SetDefaultRegionService } from "~/v3/services/setDefaultRegion.server";
6565

6666
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
6767
const user = await requireUser(request);
68-
const { projectParam } = ProjectParamSchema.parse(params);
68+
const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params);
69+
70+
const project = await findProjectBySlug(organizationSlug, projectParam, user.id);
71+
if (!project) {
72+
throw new Response(undefined, { status: 404, statusText: "Project not found" });
73+
}
74+
75+
const environment = await findEnvironmentBySlug(project.id, envParam, user.id);
76+
if (!environment) {
77+
throw new Response(undefined, { status: 404, statusText: "Environment not found" });
78+
}
6979

7080
const presenter = new RegionsPresenter();
7181
const [error, result] = await tryCatch(
7282
presenter.call({
7383
userId: user.id,
7484
projectSlug: projectParam,
85+
environmentId: environment.id,
7586
isAdmin: user.admin || user.isImpersonating,
7687
})
7788
);
@@ -106,6 +117,11 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
106117
throw redirectWithErrorMessage(redirectPath, request, "Project not found");
107118
}
108119

120+
const environment = await findEnvironmentBySlug(project.id, envParam, user.id);
121+
if (!environment) {
122+
throw redirectWithErrorMessage(redirectPath, request, "Environment not found");
123+
}
124+
109125
const formData = await request.formData();
110126
const parsedFormData = FormSchema.safeParse(Object.fromEntries(formData));
111127

@@ -116,7 +132,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
116132
const service = new SetDefaultRegionService();
117133
const [error, result] = await tryCatch(
118134
service.call({
119-
projectId: project.id,
135+
environmentId: environment.id,
120136
regionId: parsedFormData.data.regionId,
121137
isAdmin: user.admin || user.isImpersonating,
122138
})

apps/webapp/app/v3/services/setDefaultRegion.server.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { BaseService, ServiceValidationError } from "./baseService.server";
33

44
export class SetDefaultRegionService extends BaseService {
55
public async call({
6-
projectId,
6+
environmentId,
77
regionId,
88
isAdmin = false,
99
}: {
10-
projectId: string;
10+
environmentId: string;
1111
regionId: string;
1212
isAdmin?: boolean;
1313
}) {
@@ -21,23 +21,25 @@ export class SetDefaultRegionService extends BaseService {
2121
throw new ServiceValidationError("Region not found");
2222
}
2323

24-
const project = await this._prisma.project.findFirst({
24+
const environment = await this._prisma.runtimeEnvironment.findFirst({
2525
where: {
26-
id: projectId,
26+
id: environmentId,
2727
},
28-
include: {
28+
select: {
29+
id: true,
30+
project: { select: { allowedWorkerQueues: true } },
2931
organization: { select: { featureFlags: true } },
3032
},
3133
});
3234

33-
if (!project) {
34-
throw new ServiceValidationError("Project not found");
35+
if (!environment) {
36+
throw new ServiceValidationError("Environment not found");
3537
}
3638

37-
// If their project is restricted, only allow them to set default regions that are allowed
39+
// The allowlist stays project-scoped; only the default moves to the environment.
3840
if (!isAdmin) {
39-
if (project.allowedWorkerQueues.length > 0) {
40-
if (!project.allowedWorkerQueues.includes(workerGroup.masterQueue)) {
41+
if (environment.project.allowedWorkerQueues.length > 0) {
42+
if (!environment.project.allowedWorkerQueues.includes(workerGroup.masterQueue)) {
4143
throw new ServiceValidationError("You're not allowed to set this region as default");
4244
}
4345
} else {
@@ -48,7 +50,7 @@ export class SetDefaultRegionService extends BaseService {
4850
if (workerGroup.workloadType === "MICROVM") {
4951
const hasComputeAccess = await resolveComputeAccess(
5052
this._prisma,
51-
project.organization.featureFlags
53+
environment.organization.featureFlags
5254
);
5355

5456
if (!isComputeRegionAccessible(workerGroup, hasComputeAccess)) {
@@ -58,9 +60,9 @@ export class SetDefaultRegionService extends BaseService {
5860
}
5961
}
6062

61-
await this._prisma.project.update({
63+
await this._prisma.runtimeEnvironment.update({
6264
where: {
63-
id: projectId,
65+
id: environmentId,
6466
},
6567
data: {
6668
defaultWorkerGroupId: regionId,

0 commit comments

Comments
 (0)