mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-24 19:41:14 +02:00
* refactor(views): reuse AssigneePicker in CreateIssueModal Replace the hand-rolled inline assignee Popover in CreateIssueModal with the shared AssigneePicker component. This fixes missing features (private agent permission checks, lock icon, disabled state, selection checkmark) and ensures consistent behavior across all assignee dropdowns. * refactor(views): consolidate all picker components across the codebase Enhance shared pickers (StatusPicker, PriorityPicker, DueDatePicker, ProjectPicker) with triggerRender, controlled open/onOpenChange, and align props — matching the AssigneePicker API. Replace inline implementations in: - create-issue.tsx: Status, Priority, DueDate, Project (4 pickers) - issue-detail.tsx sidebar: Status, Priority (2 pickers) - batch-action-toolbar.tsx: Status, Priority (2 pickers) StatusPicker now has its first consumer (was defined but unused). Removes ~200 lines of duplicated picker code.
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
"use client";
|
|
|
|
import { Check, FolderKanban, X } from "lucide-react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { projectListOptions } from "@multica/core/projects/queries";
|
|
import { useWorkspaceId } from "@multica/core/hooks";
|
|
import type { UpdateIssueRequest } from "@multica/core/types";
|
|
import {
|
|
DropdownMenu,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuSeparator,
|
|
} from "@multica/ui/components/ui/dropdown-menu";
|
|
|
|
export function ProjectPicker({
|
|
projectId,
|
|
onUpdate,
|
|
triggerRender,
|
|
align = "start",
|
|
}: {
|
|
projectId: string | null;
|
|
onUpdate: (updates: Partial<UpdateIssueRequest>) => void;
|
|
triggerRender?: React.ReactElement;
|
|
align?: "start" | "center" | "end";
|
|
}) {
|
|
const wsId = useWorkspaceId();
|
|
const { data: projects = [] } = useQuery(projectListOptions(wsId));
|
|
const current = projects.find((p) => p.id === projectId);
|
|
|
|
return (
|
|
<DropdownMenu>
|
|
<DropdownMenuTrigger
|
|
className={triggerRender ? undefined : "flex items-center gap-1.5 cursor-pointer rounded px-1 -mx-1 hover:bg-accent/30 transition-colors overflow-hidden"}
|
|
render={triggerRender}
|
|
>
|
|
<FolderKanban className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
|
<span className="truncate">{current ? current.title : "No project"}</span>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent align={align} className="w-52">
|
|
{projects.map((p) => (
|
|
<DropdownMenuItem key={p.id} onClick={() => onUpdate({ project_id: p.id })}>
|
|
<span className="mr-1">{p.icon || "📁"}</span>
|
|
<span className="truncate">{p.title}</span>
|
|
{p.id === projectId && <Check className="ml-auto h-3.5 w-3.5 shrink-0" />}
|
|
</DropdownMenuItem>
|
|
))}
|
|
{projects.length > 0 && projectId && <DropdownMenuSeparator />}
|
|
{projectId && (
|
|
<DropdownMenuItem onClick={() => onUpdate({ project_id: null })}>
|
|
<X className="h-3.5 w-3.5 text-muted-foreground" />
|
|
Remove from project
|
|
</DropdownMenuItem>
|
|
)}
|
|
{projects.length === 0 && (
|
|
<div className="px-2 py-1.5 text-xs text-muted-foreground">No projects yet</div>
|
|
)}
|
|
</DropdownMenuContent>
|
|
</DropdownMenu>
|
|
);
|
|
}
|