create issue with assignee

This commit is contained in:
Oliver Bryan
2026-01-06 23:01:50 +00:00
parent 2e030e962e
commit efb75c2f26
4 changed files with 21 additions and 1 deletions

View File

@@ -23,8 +23,10 @@ export default async function issueCreate(req: AuthedRequest) {
const title = url.searchParams.get("title") || "Untitled Issue"; const title = url.searchParams.get("title") || "Untitled Issue";
const description = url.searchParams.get("description") || ""; const description = url.searchParams.get("description") || "";
const assigneeIdParam = url.searchParams.get("assigneeId");
const assigneeId = assigneeIdParam ? Number(assigneeIdParam) : undefined;
const issue = await createIssue(project.id, title, description, req.userId); const issue = await createIssue(project.id, title, description, req.userId, assigneeId);
return Response.json(issue); return Response.json(issue);
} }

View File

@@ -243,6 +243,7 @@ function Index() {
{selectedOrganisation && selectedProject && ( {selectedOrganisation && selectedProject && (
<CreateIssue <CreateIssue
projectId={selectedProject?.Project.id} projectId={selectedProject?.Project.id}
members={members}
completeAction={async () => { completeAction={async () => {
if (!selectedProject) return; if (!selectedProject) return;
await refetchIssues(); await refetchIssues();

View File

@@ -1,3 +1,4 @@
import type { UserRecord } from "@issue/shared";
import { type FormEvent, useState } from "react"; import { type FormEvent, useState } from "react";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
@@ -10,15 +11,18 @@ import {
} from "@/components/ui/dialog"; } from "@/components/ui/dialog";
import { Field } from "@/components/ui/field"; import { Field } from "@/components/ui/field";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import { UserSelect } from "@/components/user-select";
import { issue } from "@/lib/server"; import { issue } from "@/lib/server";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
export function CreateIssue({ export function CreateIssue({
projectId, projectId,
members,
trigger, trigger,
completeAction, completeAction,
}: { }: {
projectId?: number; projectId?: number;
members?: UserRecord[];
trigger?: React.ReactNode; trigger?: React.ReactNode;
completeAction?: (issueId: number) => void | Promise<void>; completeAction?: (issueId: number) => void | Promise<void>;
}) { }) {
@@ -27,6 +31,7 @@ export function CreateIssue({
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [assigneeId, setAssigneeId] = useState<string>("unassigned");
const [submitAttempted, setSubmitAttempted] = useState(false); const [submitAttempted, setSubmitAttempted] = useState(false);
const [submitting, setSubmitting] = useState(false); const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -34,6 +39,7 @@ export function CreateIssue({
const reset = () => { const reset = () => {
setTitle(""); setTitle("");
setDescription(""); setDescription("");
setAssigneeId("unassigned");
setSubmitAttempted(false); setSubmitAttempted(false);
setSubmitting(false); setSubmitting(false);
setError(null); setError(null);
@@ -72,6 +78,7 @@ export function CreateIssue({
projectId, projectId,
title, title,
description, description,
assigneeId: assigneeId === "unassigned" ? null : Number(assigneeId),
onSuccess: async (data) => { onSuccess: async (data) => {
setOpen(false); setOpen(false);
reset(); reset();
@@ -129,6 +136,13 @@ export function CreateIssue({
placeholder="Optional details" placeholder="Optional details"
/> />
{members && members.length > 0 && (
<div className="flex items-center gap-2 mt-2">
<Label className="text-sm">Assignee</Label>
<UserSelect users={members} value={assigneeId} onChange={setAssigneeId} />
</div>
)}
<div className="flex items-end justify-end w-full text-xs -mb-2 -mt-2"> <div className="flex items-end justify-end w-full text-xs -mb-2 -mt-2">
{error ? ( {error ? (
<Label className="text-destructive text-sm">{error}</Label> <Label className="text-destructive text-sm">{error}</Label>

View File

@@ -5,17 +5,20 @@ export async function create({
projectId, projectId,
title, title,
description, description,
assigneeId,
onSuccess, onSuccess,
onError, onError,
}: { }: {
projectId: number; projectId: number;
title: string; title: string;
description: string; description: string;
assigneeId?: number | null;
} & ServerQueryInput) { } & ServerQueryInput) {
const url = new URL(`${getServerURL()}/issue/create`); const url = new URL(`${getServerURL()}/issue/create`);
url.searchParams.set("projectId", `${projectId}`); url.searchParams.set("projectId", `${projectId}`);
url.searchParams.set("title", title.trim()); url.searchParams.set("title", title.trim());
if (description.trim() !== "") url.searchParams.set("description", description.trim()); if (description.trim() !== "") url.searchParams.set("description", description.trim());
if (assigneeId != null) url.searchParams.set("assigneeId", `${assigneeId}`);
const res = await fetch(url.toString(), { const res = await fetch(url.toString(), {
headers: getAuthHeaders(), headers: getAuthHeaders(),