Skip to main content
Glama

Sentry MCP

Official
by getsentry
chat-input.tsx4.57 kB
import { useEffect, useRef } from "react"; import { Send, CircleStop } from "lucide-react"; import { Button } from "../ui/button"; interface ChatInputProps { input: string; isLoading: boolean; isOpen: boolean; onInputChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void; onSubmit: (e: React.FormEvent<HTMLFormElement>) => void; onStop: () => void; onSlashCommand?: (command: string) => void; } export function ChatInput({ input, isLoading, isOpen, onInputChange, onSubmit, onStop, onSlashCommand, }: ChatInputProps) { const inputRef = useRef<HTMLTextAreaElement>(null); // Focus when dialog opens (with delay for mobile animation) useEffect(() => { if (isOpen) { // Add delay to ensure the slide-in animation completes on mobile const timer = setTimeout(() => { // Use requestAnimationFrame to ensure browser has finished layout requestAnimationFrame(() => { if (inputRef.current && !inputRef.current.disabled) { inputRef.current.focus({ preventScroll: false }); } }); }, 600); // Delay to account for 500ms animation return () => clearTimeout(timer); } }, [isOpen]); // Re-focus when loading finishes useEffect(() => { if (inputRef.current && !isLoading && isOpen) { inputRef.current.focus(); } }, [isLoading, isOpen]); const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); // Check if input is a slash command if (input.startsWith("/") && onSlashCommand) { const command = input.slice(1).toLowerCase().trim(); // Pass all slash commands to the handler, let it decide what to do onSlashCommand(command); return; } // Otherwise, submit normally onSubmit(e); }; // Handle keyboard shortcuts const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => { // Ctrl+J or Cmd+J: Insert newline if ((e.ctrlKey || e.metaKey) && e.key === "j") { e.preventDefault(); const textarea = e.currentTarget; const start = textarea.selectionStart; const end = textarea.selectionEnd; const newValue = `${input.substring(0, start)}\n${input.substring(end)}`; // Create a synthetic event to update the input const syntheticEvent = { target: { value: newValue }, currentTarget: { value: newValue }, } as React.ChangeEvent<HTMLTextAreaElement>; onInputChange(syntheticEvent); // Move cursor after the inserted newline setTimeout(() => { if (textarea) { textarea.selectionStart = textarea.selectionEnd = start + 1; } }, 0); return; } // Enter without shift: Submit if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey) { e.preventDefault(); const form = e.currentTarget.form; if (form && input.trim()) { form.requestSubmit(); } } }; // Auto-resize textarea based on content // biome-ignore lint/correctness/useExhaustiveDependencies: input is needed to trigger resize when content changes useEffect(() => { if (inputRef.current) { inputRef.current.style.height = "auto"; inputRef.current.style.height = `${inputRef.current.scrollHeight}px`; } }, [input]); return ( <form onSubmit={handleSubmit} className="relative flex-1"> <div className="relative"> <textarea ref={inputRef} value={input} onChange={onInputChange} onKeyDown={handleKeyDown} placeholder="Ask me anything about your Sentry data..." disabled={isLoading} rows={1} className="w-full p-4 pr-12 rounded bg-slate-800/50 text-white placeholder-slate-400 focus:outline-none focus:ring-2 focus:ring-violet-300 focus:border-transparent disabled:opacity-50 resize-none overflow-hidden" /> <Button type={isLoading ? "button" : "submit"} variant="ghost" onClick={isLoading ? onStop : undefined} disabled={!isLoading && !input.trim()} className="absolute right-2 top-1/2 -translate-y-1/2 p-2 text-slate-400 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:text-slate-400 disabled:hover:bg-transparent transition-colors" title={isLoading ? "Stop generation" : "Send message"} > {isLoading ? ( <CircleStop className="h-4 w-4" /> ) : ( <Send className="h-4 w-4" /> )} </Button> </div> </form> ); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/getsentry/sentry-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server