feat(frontend): add repo type to mention autocomplete system

Add 'repo' to MentionType across all editor types, include repos in the
@ trigger pool, add repo badge (green chip), Repos section in the
mention dropdown, and MentionBadge styles. Wire projectRepos from
room context into IMEditor mentionItems.
This commit is contained in:
ZhenYi 2026-04-26 23:58:59 +08:00
parent adbc0705db
commit c8eba28e7a
5 changed files with 28 additions and 6 deletions

View File

@ -76,7 +76,7 @@ export const MessageInput = forwardRef<MessageInputHandle, MessageInputProps>(fu
{roomName, onSend, replyingTo, onCancelReply},
ref,
) {
const {members, activeRoomId, roomAiConfigs, wsClient} = useRoom();
const {members, activeRoomId, roomAiConfigs, projectRepos, wsClient} = useRoom();
// Ref passed to the inner IMEditor
const innerEditorRef = useRef<IMEditorHandle | null>(null);
@ -147,12 +147,18 @@ export const MessageInput = forwardRef<MessageInputHandle, MessageInputProps>(fu
channels: [] as { id: string; label: string; type: 'channel'; avatar?: string }[],
ai: roomAiConfigs.map((cfg) => ({
id: cfg.model,
label: cfg.modelName ?? cfg.model,
label: cfg.modelName || 'Unknown AI',
type: 'ai' as const,
})),
repos: projectRepos.map((r) => ({
id: r.repo_name,
label: r.repo_name,
type: 'repo' as const,
description: r.description ?? undefined,
})),
commands: SLASH_COMMANDS,
specialMentions: SPECIAL_MENTIONS,
}), [members, roomAiConfigs]);
}), [members, roomAiConfigs, projectRepos]);
// File upload handler — POST to /rooms/{room_id}/upload
const handleUploadFile = async (file: File): Promise<{ id: string; url: string }> => {

View File

@ -26,6 +26,7 @@ export interface IMEditorProps {
users: MentionItem[];
channels: MentionItem[];
ai: MentionItem[];
repos: MentionItem[];
commands: MentionItem[];
specialMentions?: MentionItem[];
};
@ -151,6 +152,7 @@ function getBadge(type: MentionType): { label: string; cls: string } | null {
if (type === 'ai') return {label: 'AI', cls: 'bg-blue-50 text-blue-600'};
if (type === 'channel') return {label: '#', cls: 'bg-gray-100 text-gray-500'};
if (type === 'command') return {label: 'cmd', cls: 'bg-amber-50 text-amber-600'};
if (type === 'repo') return {label: 'repo', cls: 'bg-green-50 text-green-600'};
return null;
}
@ -173,12 +175,13 @@ function serializeAstNode(node: EditorNode): string {
// ─── Mention Dropdown (sectioned by type) ────────────────────────────────────
const SECTION_ORDER = ['special_here', 'special_channel', 'ai', 'user', 'channel', 'command'] as const;
const SECTION_ORDER = ['special_here', 'special_channel', 'ai', 'user', 'repo', 'channel', 'command'] as const;
const SECTION_LABELS: Record<string, string> = {
special_here: 'Notify',
special_channel: 'Notify',
ai: 'AI',
user: 'Members',
repo: 'Repositories',
channel: 'Channels',
command: 'Commands',
};
@ -356,7 +359,8 @@ export const IMEditor = forwardRef<IMEditorHandle, IMEditorProps>(function IMEdi
...(mentionItems.specialMentions ?? []),
...mentionItems.ai,
...mentionItems.users,
], [mentionItems.specialMentions, mentionItems.ai, mentionItems.users]);
...mentionItems.repos,
], [mentionItems.specialMentions, mentionItems.ai, mentionItems.users, mentionItems.repos]);
const hashPool = useMemo(() => [...mentionItems.channels], [mentionItems.channels]);

View File

@ -2,7 +2,7 @@
* Core types for the IM editor (mentions, files, emojis).
*/
export type MentionType = 'user' | 'channel' | 'ai' | 'command' | 'special_here' | 'special_channel';
export type MentionType = 'user' | 'channel' | 'ai' | 'repo' | 'command' | 'special_here' | 'special_channel';
export interface MentionItem {
id: string;

View File

@ -42,6 +42,11 @@ const TYPE_STYLE: Record<MentionType, { light: string; dark?: string; prefix: st
dark: 'dark:bg-orange-900/30 dark:text-orange-300',
prefix: '@',
},
repo: {
light: 'bg-teal-50 text-teal-600',
dark: 'dark:bg-teal-900/30 dark:text-teal-300',
prefix: '@',
},
};
export function MentionBadge({ type, label, onClick, id, className }: MentionBadgeProps) {

View File

@ -7,6 +7,7 @@ export type MentionType =
| 'user'
| 'channel'
| 'ai'
| 'repo'
| 'command'
| 'special_here'
| 'special_channel';
@ -15,6 +16,7 @@ export const MENTION_TYPES: MentionType[] = [
'user',
'channel',
'ai',
'repo',
'command',
'special_here',
'special_channel',
@ -84,6 +86,11 @@ export function serializeAiMention(aiId: string, aiName: string): string {
return serializeMention('ai', aiId, aiName);
}
/** Build a mention token from a repo mention. */
export function serializeRepoMention(repoName: string, label?: string): string {
return serializeMention('repo', repoName, label ?? repoName);
}
/** Build a mention token from a command mention. */
export function serializeCommandMention(commandId: string, commandName: string): string {
return serializeMention('command', commandId, commandName);