mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-17 03:10:38 +09:00
feat: @project mentions with colored chips in markdown and editors
Add project mention system using project:// URI scheme with optional color parameter. Mentions render as colored pill chips in markdown bodies and the WYSIWYG editor. Autocomplete in editors shows both agents and projects. Server extracts mentioned project IDs from issue content and returns them in the issue detail response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
19e2cf3793
commit
2488dc703c
13 changed files with 397 additions and 13 deletions
|
|
@ -17,6 +17,7 @@ import { InlineEditor } from "../components/InlineEditor";
|
|||
import { CommentThread } from "../components/CommentThread";
|
||||
import { IssueProperties } from "../components/IssueProperties";
|
||||
import { LiveRunWidget } from "../components/LiveRunWidget";
|
||||
import type { MentionOption } from "../components/MarkdownEditor";
|
||||
import { StatusIcon } from "../components/StatusIcon";
|
||||
import { PriorityIcon } from "../components/PriorityIcon";
|
||||
import { StatusBadge } from "../components/StatusBadge";
|
||||
|
|
@ -234,6 +235,31 @@ export function IssueDetail() {
|
|||
return map;
|
||||
}, [agents]);
|
||||
|
||||
const mentionOptions = useMemo<MentionOption[]>(() => {
|
||||
const options: MentionOption[] = [];
|
||||
const activeAgents = [...(agents ?? [])]
|
||||
.filter((agent) => agent.status !== "terminated")
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
for (const agent of activeAgents) {
|
||||
options.push({
|
||||
id: `agent:${agent.id}`,
|
||||
name: agent.name,
|
||||
kind: "agent",
|
||||
});
|
||||
}
|
||||
const sortedProjects = [...(projects ?? [])].sort((a, b) => a.name.localeCompare(b.name));
|
||||
for (const project of sortedProjects) {
|
||||
options.push({
|
||||
id: `project:${project.id}`,
|
||||
name: project.name,
|
||||
kind: "project",
|
||||
projectId: project.id,
|
||||
projectColor: project.color,
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}, [agents, projects]);
|
||||
|
||||
const childIssues = useMemo(() => {
|
||||
if (!allIssues || !issue) return [];
|
||||
return allIssues
|
||||
|
|
@ -609,6 +635,7 @@ export function IssueDetail() {
|
|||
className="text-sm text-muted-foreground"
|
||||
placeholder="Add a description..."
|
||||
multiline
|
||||
mentions={mentionOptions}
|
||||
imageUploadHandler={async (file) => {
|
||||
const attachment = await uploadAttachment.mutateAsync(file);
|
||||
return attachment.contentPath;
|
||||
|
|
@ -715,6 +742,7 @@ export function IssueDetail() {
|
|||
draftKey={`paperclip:issue-comment-draft:${issue.id}`}
|
||||
enableReassign={canReassignFromComment}
|
||||
reassignOptions={commentReassignOptions}
|
||||
mentions={mentionOptions}
|
||||
onAdd={async (body, reopen, reassignment) => {
|
||||
if (reassignment) {
|
||||
await addCommentAndReassign.mutateAsync({ body, reopen, reassignment });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue