|
7 | 7 | MapPinIcon, |
8 | 8 | } from "@heroicons/react/20/solid"; |
9 | 9 | import { Form } from "@remix-run/react"; |
10 | | -import { type ActionFunctionArgs, type LoaderFunctionArgs } from "@remix-run/server-runtime"; |
| 10 | +import { type LoaderFunctionArgs } from "@remix-run/server-runtime"; |
11 | 11 | import { tryCatch } from "@trigger.dev/core"; |
12 | 12 | import { useState } from "react"; |
13 | 13 | import { typedjson, useTypedLoaderData } from "remix-typedjson"; |
@@ -51,9 +51,11 @@ import { useFeatures } from "~/hooks/useFeatures"; |
51 | 51 | import { useOrganization } from "~/hooks/useOrganizations"; |
52 | 52 | import { useHasAdminAccess } from "~/hooks/useUser"; |
53 | 53 | import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server"; |
| 54 | +import { resolveOrgIdFromSlug } from "~/models/organization.server"; |
54 | 55 | import { findProjectBySlug } from "~/models/project.server"; |
55 | 56 | import { type Region, RegionsPresenter } from "~/presenters/v3/RegionsPresenter.server"; |
56 | 57 | import { requireUser } from "~/services/session.server"; |
| 58 | +import { dashboardAction } from "~/services/routeBuilders/dashboardBuilder"; |
57 | 59 | import { |
58 | 60 | docsPath, |
59 | 61 | EnvironmentParamSchema, |
@@ -90,44 +92,60 @@ const FormSchema = z.object({ |
90 | 92 | regionId: z.string(), |
91 | 93 | }); |
92 | 94 |
|
93 | | -export const action = async ({ request, params }: ActionFunctionArgs) => { |
94 | | - const user = await requireUser(request); |
95 | | - const { organizationSlug, projectParam, envParam } = EnvironmentParamSchema.parse(params); |
| 95 | +export const action = dashboardAction( |
| 96 | + { |
| 97 | + params: EnvironmentParamSchema, |
| 98 | + context: async (params) => { |
| 99 | + const orgId = await resolveOrgIdFromSlug(params.organizationSlug); |
| 100 | + return orgId ? { organizationId: orgId } : {}; |
| 101 | + }, |
| 102 | + }, |
| 103 | + async ({ user, ability, request, params }) => { |
| 104 | + const { organizationSlug, projectParam, envParam } = params; |
96 | 105 |
|
97 | | - const project = await findProjectBySlug(organizationSlug, projectParam, user.id); |
| 106 | + const redirectPath = regionsPath( |
| 107 | + { slug: organizationSlug }, |
| 108 | + { slug: projectParam }, |
| 109 | + { slug: envParam } |
| 110 | + ); |
98 | 111 |
|
99 | | - const redirectPath = regionsPath( |
100 | | - { slug: organizationSlug }, |
101 | | - { slug: projectParam }, |
102 | | - { slug: envParam } |
103 | | - ); |
| 112 | + if (!ability.can("manage", { type: "project" })) { |
| 113 | + throw await redirectWithErrorMessage( |
| 114 | + redirectPath, |
| 115 | + request, |
| 116 | + "You don't have permission to change the default region" |
| 117 | + ); |
| 118 | + } |
104 | 119 |
|
105 | | - if (!project) { |
106 | | - throw await redirectWithErrorMessage(redirectPath, request, "Project not found"); |
107 | | - } |
| 120 | + const project = await findProjectBySlug(organizationSlug, projectParam, user.id); |
108 | 121 |
|
109 | | - const formData = await request.formData(); |
110 | | - const parsedFormData = FormSchema.safeParse(Object.fromEntries(formData)); |
| 122 | + if (!project) { |
| 123 | + throw await redirectWithErrorMessage(redirectPath, request, "Project not found"); |
| 124 | + } |
111 | 125 |
|
112 | | - if (!parsedFormData.success) { |
113 | | - throw await redirectWithErrorMessage(redirectPath, request, "No region specified"); |
114 | | - } |
| 126 | + const formData = await request.formData(); |
| 127 | + const parsedFormData = FormSchema.safeParse(Object.fromEntries(formData)); |
115 | 128 |
|
116 | | - const service = new SetDefaultRegionService(); |
117 | | - const [error, result] = await tryCatch( |
118 | | - service.call({ |
119 | | - projectId: project.id, |
120 | | - regionId: parsedFormData.data.regionId, |
121 | | - isAdmin: user.admin || user.isImpersonating, |
122 | | - }) |
123 | | - ); |
| 129 | + if (!parsedFormData.success) { |
| 130 | + throw await redirectWithErrorMessage(redirectPath, request, "No region specified"); |
| 131 | + } |
124 | 132 |
|
125 | | - if (error) { |
126 | | - return redirectWithErrorMessage(redirectPath, request, error.message); |
127 | | - } |
| 133 | + const service = new SetDefaultRegionService(); |
| 134 | + const [error, result] = await tryCatch( |
| 135 | + service.call({ |
| 136 | + projectId: project.id, |
| 137 | + regionId: parsedFormData.data.regionId, |
| 138 | + isAdmin: user.admin || user.isImpersonating, |
| 139 | + }) |
| 140 | + ); |
128 | 141 |
|
129 | | - return redirectWithSuccessMessage(redirectPath, request, `Set ${result.name} as default`); |
130 | | -}; |
| 142 | + if (error) { |
| 143 | + return redirectWithErrorMessage(redirectPath, request, error.message); |
| 144 | + } |
| 145 | + |
| 146 | + return redirectWithSuccessMessage(redirectPath, request, `Set ${result.name} as default`); |
| 147 | + } |
| 148 | +); |
131 | 149 |
|
132 | 150 | export default function Page() { |
133 | 151 | const { regions, isPaying: _isPaying } = useTypedLoaderData<typeof loader>(); |
|
0 commit comments