| 1 | // The forms of the milestones pages: create, edit, close or reopen, delete. |
| 2 | // Each needs the Triage role, which work checks again. |
| 3 | |
| 4 | import type { MilestoneResult } from "../components/milestones"; |
| 5 | import { refusal } from "./access.server"; |
| 6 | import { work } from "./services.server"; |
| 7 | import { assertSameOrigin, requireUser } from "./session.server"; |
| 8 | |
| 9 | type Context = Parameters<typeof refusal>[0]; |
| 10 | type RepoParams = Parameters<typeof refusal>[1]; |
| 11 | |
| 12 | export async function milestoneAction(request: Request, params: RepoParams, context: Context): Promise<MilestoneResult> { |
| 13 | assertSameOrigin(request); |
| 14 | const user = requireUser(context, request); |
| 15 | const form = await request.formData(); |
| 16 | const intent = String(form.get("intent") ?? ""); |
| 17 | const number = Number(form.get("number")) || undefined; |
| 18 | const refused = await refusal(context, params, "triage"); |
| 19 | if (refused) return { intent, number, error: refused }; |
| 20 | const path = { namespace: params.owner ?? "", name: params.repo ?? "" }; |
| 21 | const text = (key: string) => (form.has(key) ? String(form.get(key) ?? "") : undefined); |
| 22 | if (intent === "delete") { |
| 23 | const deleted = await work.deleteMilestone(user, path, number ?? 0); |
| 24 | return deleted.ok ? { intent, number } : { intent, number, error: deleted.error.message }; |
| 25 | } |
| 26 | const state = form.get("state"); |
| 27 | const saved = await work.saveMilestone(user, path, { |
| 28 | number: intent === "create" ? undefined : number, |
| 29 | title: text("title"), |
| 30 | description: text("description"), |
| 31 | dueOn: text("dueOn"), |
| 32 | state: state === "open" || state === "closed" ? state : undefined, |
| 33 | }); |
| 34 | return saved.ok ? { intent, number: saved.value.number } : { intent, number, error: saved.error.message }; |
| 35 | } |