Skip to content

Commit 56aa39e

Browse files
committed
Type formAction for better editor support
1 parent dc182d5 commit 56aa39e

File tree

1 file changed

+114
-107
lines changed
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam

1 file changed

+114
-107
lines changed

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

Lines changed: 114 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "~/components
7575
import { DialogClose, DialogDescription } from "@radix-ui/react-dialog";
7676
import { FormButtons } from "~/components/primitives/FormButtons";
7777

78+
type FormAction = "create-template" | "delete-template" | "run-scheduled" | "run-standard";
79+
7880
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
7981
const userId = await requireUserId(request);
8082
const { projectParam, organizationSlug, envParam, taskParam } = v3TaskParamsSchema.parse(params);
@@ -130,109 +132,114 @@ export const action: ActionFunction = async ({ request, params }) => {
130132
}
131133

132134
const formData = await request.formData();
133-
const formAction = formData.get("formAction");
134-
135-
// Handle run template creation
136-
if (formAction === "create-template") {
137-
const submission = parse(formData, { schema: RunTemplateData });
138-
if (!submission.value) {
139-
return json({
140-
...submission,
141-
formAction,
142-
});
143-
}
144-
145-
const templateService = new TaskRunTemplateService();
146-
try {
147-
const template = await templateService.call(environment, submission.value);
148-
149-
return json({
150-
...submission,
151-
success: true,
152-
templateLabel: template.label,
153-
formAction,
154-
});
155-
} catch (e) {
156-
logger.error("Failed to create template", { error: e instanceof Error ? e.message : e });
157-
return redirectBackWithErrorMessage(request, "Failed to create template");
158-
}
159-
}
160-
161-
// Handle run template deletion
162-
if (formAction === "delete-template") {
163-
const submission = parse(formData, { schema: DeleteTaskRunTemplateData });
164-
165-
if (!submission.value) {
166-
return json({
167-
...submission,
168-
formAction,
169-
});
135+
const formAction = formData.get("formAction") as FormAction;
136+
137+
switch (formAction) {
138+
case "create-template": {
139+
const submission = parse(formData, { schema: RunTemplateData });
140+
if (!submission.value) {
141+
return json({
142+
...submission,
143+
formAction,
144+
});
145+
}
146+
147+
const templateService = new TaskRunTemplateService();
148+
try {
149+
const template = await templateService.call(environment, submission.value);
150+
151+
return json({
152+
...submission,
153+
success: true,
154+
templateLabel: template.label,
155+
formAction,
156+
});
157+
} catch (e) {
158+
logger.error("Failed to create template", { error: e instanceof Error ? e.message : e });
159+
return redirectBackWithErrorMessage(request, "Failed to create template");
160+
}
170161
}
171-
172-
const deleteService = new DeleteTaskRunTemplateService();
173-
try {
174-
await deleteService.call(environment, submission.value.templateId);
175-
176-
return json({
177-
...submission,
178-
success: true,
179-
formAction,
180-
});
181-
} catch (e) {
182-
logger.error("Failed to delete template", { error: e instanceof Error ? e.message : e });
183-
return redirectBackWithErrorMessage(request, "Failed to delete template");
162+
case "delete-template": {
163+
const submission = parse(formData, { schema: DeleteTaskRunTemplateData });
164+
165+
if (!submission.value) {
166+
return json({
167+
...submission,
168+
formAction,
169+
});
170+
}
171+
172+
const deleteService = new DeleteTaskRunTemplateService();
173+
try {
174+
await deleteService.call(environment, submission.value.templateId);
175+
176+
return json({
177+
...submission,
178+
success: true,
179+
formAction,
180+
});
181+
} catch (e) {
182+
logger.error("Failed to delete template", { error: e instanceof Error ? e.message : e });
183+
return redirectBackWithErrorMessage(request, "Failed to delete template");
184+
}
184185
}
185-
}
186-
187-
const submission = parse(formData, { schema: TestTaskData });
188-
189-
if (!submission.value) {
190-
return json({
191-
...submission,
192-
formAction,
193-
});
194-
}
195-
196-
if (environment.archivedAt) {
197-
return redirectBackWithErrorMessage(request, "Can't run a test on an archived environment");
198-
}
199-
200-
const testService = new TestTaskService();
201-
try {
202-
const run = await testService.call(environment, submission.value);
203-
204-
if (!run) {
205-
return redirectBackWithErrorMessage(
206-
request,
207-
"Unable to start a test run: Something went wrong"
208-
);
186+
case "run-scheduled":
187+
case "run-standard": {
188+
const submission = parse(formData, { schema: TestTaskData });
189+
190+
if (!submission.value) {
191+
return json({
192+
...submission,
193+
formAction,
194+
});
195+
}
196+
197+
if (environment.archivedAt) {
198+
return redirectBackWithErrorMessage(request, "Can't run a test on an archived environment");
199+
}
200+
201+
const testService = new TestTaskService();
202+
try {
203+
const run = await testService.call(environment, submission.value);
204+
205+
if (!run) {
206+
return redirectBackWithErrorMessage(
207+
request,
208+
"Unable to start a test run: Something went wrong"
209+
);
210+
}
211+
212+
return redirectWithSuccessMessage(
213+
v3RunSpanPath(
214+
{ slug: organizationSlug },
215+
{ slug: projectParam },
216+
{ slug: envParam },
217+
{ friendlyId: run.friendlyId },
218+
{ spanId: run.spanId }
219+
),
220+
request,
221+
"Test run created"
222+
);
223+
} catch (e) {
224+
if (e instanceof OutOfEntitlementError) {
225+
return redirectBackWithErrorMessage(
226+
request,
227+
"Unable to start a test run: You have exceeded your free credits"
228+
);
229+
}
230+
231+
logger.error("Failed to start a test run", { error: e instanceof Error ? e.message : e });
232+
233+
return redirectBackWithErrorMessage(
234+
request,
235+
"Unable to start a test run: Something went wrong"
236+
);
237+
}
209238
}
210-
211-
return redirectWithSuccessMessage(
212-
v3RunSpanPath(
213-
{ slug: organizationSlug },
214-
{ slug: projectParam },
215-
{ slug: envParam },
216-
{ friendlyId: run.friendlyId },
217-
{ spanId: run.spanId }
218-
),
219-
request,
220-
"Test run created"
221-
);
222-
} catch (e) {
223-
if (e instanceof OutOfEntitlementError) {
224-
return redirectBackWithErrorMessage(
225-
request,
226-
"Unable to start a test run: You have exceeded your free credits"
227-
);
239+
default: {
240+
formAction satisfies never;
241+
return redirectBackWithErrorMessage(request, "Failed to process request");
228242
}
229-
230-
logger.error("Failed to start a test run", { error: e instanceof Error ? e.message : e });
231-
232-
return redirectBackWithErrorMessage(
233-
request,
234-
"Unable to start a test run: Something went wrong"
235-
);
236243
}
237244
};
238245

@@ -334,7 +341,7 @@ function StandardTaskForm({
334341
actionData &&
335342
typeof actionData === "object" &&
336343
"formAction" in actionData &&
337-
actionData.formAction === "run-standard"
344+
actionData.formAction === ("run-standard" satisfies FormAction)
338345
? actionData
339346
: undefined;
340347

@@ -768,7 +775,7 @@ function StandardTaskForm({
768775
LeadingIcon={BeakerIcon}
769776
shortcut={{ key: "enter", modifiers: ["mod"], enabledOnInputElements: true }}
770777
name="formAction"
771-
value="run-standard"
778+
value={"run-standard" satisfies FormAction}
772779
>
773780
Run test
774781
</Button>
@@ -839,7 +846,7 @@ function ScheduledTaskForm({
839846
actionData &&
840847
typeof actionData === "object" &&
841848
"formAction" in actionData &&
842-
actionData.formAction === "run-scheduled"
849+
actionData.formAction === ("run-scheduled" satisfies FormAction)
843850
? actionData
844851
: undefined;
845852

@@ -1277,7 +1284,7 @@ function ScheduledTaskForm({
12771284
LeadingIcon={BeakerIcon}
12781285
shortcut={{ key: "enter", modifiers: ["mod"], enabledOnInputElements: true }}
12791286
name="formAction"
1280-
value="run-scheduled"
1287+
value={"run-scheduled" satisfies FormAction}
12811288
>
12821289
Run test
12831290
</Button>
@@ -1359,7 +1366,7 @@ function RunTemplatesPopover({
13591366
actionData &&
13601367
typeof actionData === "object" &&
13611368
"formAction" in actionData &&
1362-
actionData.formAction === "delete-template"
1369+
actionData.formAction === ("delete-template" satisfies FormAction)
13631370
? actionData
13641371
: undefined;
13651372

@@ -1498,7 +1505,7 @@ function RunTemplatesPopover({
14981505
variant="danger/medium"
14991506
LeadingIcon={TrashIcon}
15001507
name="formAction"
1501-
value="delete-template"
1508+
value={"delete-template" satisfies FormAction}
15021509
>
15031510
Delete
15041511
</Button>
@@ -1545,7 +1552,7 @@ function CreateTemplateModal({
15451552
actionData &&
15461553
typeof actionData === "object" &&
15471554
"formAction" in actionData &&
1548-
actionData.formAction === "create-template"
1555+
actionData.formAction === ("create-template" satisfies FormAction)
15491556
? actionData
15501557
: undefined;
15511558

@@ -1690,7 +1697,7 @@ function CreateTemplateModal({
16901697
type="submit"
16911698
variant="primary/medium"
16921699
name="formAction"
1693-
value="create-template"
1700+
value={"create-template" satisfies FormAction}
16941701
>
16951702
Create template
16961703
</Button>

0 commit comments

Comments
 (0)