gitdataai/src/lib/mention.ts
ZhenYi dfa5f7664a feat: add notification drawer, command registry, keyboard shortcuts, hooks
New components:
- NotificationDrawer: global bell button with unread badge + Sheet drawer
- CommandPalette: Cmd+K / Ctrl+Alt+F command palette with real API data
- KeyboardShortcutsSheet: ? shortcut reference sheet
- GlobalNavigationShortcuts: g+n/i/r/m two-key navigation
- useNotification: real-time notification management hook
- useCommandRegistry: global command registration hook
- useKeyboardShortcut: keyboard shortcut formatting hook
- useTypingIndicator: unified typing indicator hook
- LinkPreview / CodeBlock / CodeReference: code-aware chat rendering
- ContentRenderer: unified content rendering
- MiniChat: compact inline chat component
- MentionBadge: @mention badge renderer

New libs:
- libs/api/agent/issue_triage.rs: AI issue triage API endpoint
- libs/service/agent/issue_triage.rs: AI triage service
- src/lib/mention.ts: mention parsing and rendering
- src/lib/link-unfurl.ts: URL pattern detection
- src/lib/code-lang-detect.ts: code language detection
- src/lib/code-ref-parser.ts: line-level code reference parsing
2026-04-25 09:53:49 +08:00

101 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Unified mention serialization and parsing utilities.
* Shared across room chat, issues, and PR comments.
*/
export type MentionType =
| 'user'
| 'channel'
| 'ai'
| 'command'
| 'special_here'
| 'special_channel';
export const MENTION_TYPES: MentionType[] = [
'user',
'channel',
'ai',
'command',
'special_here',
'special_channel',
];
export interface MentionSpan {
type: MentionType;
id: string;
label: string;
}
export interface ExtractedMentions {
safeContent: string;
mentions: MentionSpan[];
}
/**
* Parse @[type:id:label] tokens from message content.
* Returns the safe content (with mentions replaced by placeholders) and the parsed mention list.
*
* Placeholders use zero-width spaces to prevent markdown from interpreting the text.
*/
const PLACEHOLDER_PREFIX = 'MENTION_';
const PLACEHOLDER_SUFFIX = '';
const MENTION_RE = /@\[([a-z_]+):([^:\]]+):([^\]]+)\]/g;
const PLACEHOLDER_RE = /MENTION_(\d+)/g;
export function extractMentions(content: string): ExtractedMentions {
const mentions: MentionSpan[] = [];
const safeContent = content.replace(MENTION_RE, (_match, type, id, label) => {
const idx = mentions.length;
mentions.push({ type: type as MentionType, id, label });
return `${PLACEHOLDER_PREFIX}${idx}${PLACEHOLDER_SUFFIX}`;
});
return { safeContent, mentions };
}
export function restoreMentions(
text: string,
mentions: MentionSpan[],
): string {
return text.replace(PLACEHOLDER_RE, (match, idxStr) => {
const idx = parseInt(idxStr, 10);
const m = mentions[idx];
return m ? `@[${m.type}:${m.id}:${m.label}]` : match;
});
}
/** Build a mention token string for serialization. */
export function serializeMention(type: MentionType, id: string, label: string): string {
return `@[${type}:${id}:${label}]`;
}
/** Build a mention token from a user mention. */
export function serializeUserMention(userId: string, displayName: string): string {
return serializeMention('user', userId, displayName);
}
/** Build a mention token from a channel mention. */
export function serializeChannelMention(channelId: string, channelName: string): string {
return serializeMention('channel', channelId, channelName);
}
/** Build a mention token from an AI mention. */
export function serializeAiMention(aiId: string, aiName: string): string {
return serializeMention('ai', aiId, aiName);
}
/** Build a mention token from a command mention. */
export function serializeCommandMention(commandId: string, commandName: string): string {
return serializeMention('command', commandId, commandName);
}
/** Build a mention token for @here. */
export function serializeHereMention(): string {
return '@[special_here:here:here]';
}
/** Build a mention token for @channel. */
export function serializeChannelBroadcastMention(): string {
return '@[special_channel:channel:channel]';
}