Add problems option to context menu

This commit is contained in:
Saoud Rizwan
2024-09-17 15:21:36 -04:00
parent d47008f0b4
commit 7e91e7aecb
3 changed files with 42 additions and 10 deletions

View File

@@ -87,6 +87,9 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
} else if (type === "file" || type === "folder") { } else if (type === "file" || type === "folder") {
// For files and folders, we insert the path // For files and folders, we insert the path
insertValue = value insertValue = value
} else if (type === "problems") {
// For workspace problems, we insert @problems
insertValue = "problems"
} }
const newValue = insertMention(textAreaRef.current.value, cursorPosition, insertValue) const newValue = insertMention(textAreaRef.current.value, cursorPosition, insertValue)
@@ -105,6 +108,12 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
(event: React.KeyboardEvent<HTMLTextAreaElement>) => { (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (showContextMenu) { if (showContextMenu) {
if (event.key === "Escape") {
// event.preventDefault()
setShowContextMenu(false)
return
}
if (event.key === "ArrowUp" || event.key === "ArrowDown") { if (event.key === "ArrowUp" || event.key === "ArrowDown") {
event.preventDefault() event.preventDefault()
setSelectedMenuIndex((prevIndex) => { setSelectedMenuIndex((prevIndex) => {
@@ -159,7 +168,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
charAfterCursor === " " || charAfterCursor === "\n" || charAfterCursor === "\r\n" charAfterCursor === " " || charAfterCursor === "\n" || charAfterCursor === "\r\n"
if ( if (
charBeforeIsWhitespace && charBeforeIsWhitespace &&
inputValue.slice(0, cursorPosition - 1).match(/@(\/|\w+:\/\/)[^\s]+$/) inputValue.slice(0, cursorPosition - 1).match(/@((?:\/|\w+:\/\/)[^\s]+|problems)$/)
) { ) {
const newCursorPosition = cursorPosition - 1 const newCursorPosition = cursorPosition - 1
if (!charAfterIsWhitespace) { if (!charAfterIsWhitespace) {
@@ -220,7 +229,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
if (query.length > 0) { if (query.length > 0) {
setSelectedMenuIndex(0) setSelectedMenuIndex(0)
} else { } else {
setSelectedMenuIndex(2) // Set to "File" option by default setSelectedMenuIndex(3) // Set to "File" option by default
} }
} else { } else {
setSearchQuery("") setSearchQuery("")
@@ -230,6 +239,12 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
[setInputValue] [setInputValue]
) )
useEffect(() => {
if (!showContextMenu) {
setSelectedType(null)
}
}, [showContextMenu])
const handleBlur = useCallback(() => { const handleBlur = useCallback(() => {
// Only hide the context menu if the user didn't click on it // Only hide the context menu if the user didn't click on it
if (!isMouseDownOnMenu) { if (!isMouseDownOnMenu) {
@@ -299,7 +314,7 @@ const ChatTextArea = forwardRef<HTMLTextAreaElement, ChatTextAreaProps>(
if (!textAreaRef.current || !highlightLayerRef.current) return if (!textAreaRef.current || !highlightLayerRef.current) return
const text = textAreaRef.current.value const text = textAreaRef.current.value
const mentionRegex = /@(\/|\w+:\/\/)[^\s]+/g const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/g
highlightLayerRef.current.innerHTML = text highlightLayerRef.current.innerHTML = text
.replace(/\n$/, "\n\n") .replace(/\n$/, "\n\n")

View File

@@ -88,6 +88,8 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
? "Add file" ? "Add file"
: option.value === "Folder" : option.value === "Folder"
? "Add folder" ? "Add folder"
: option.value === "Problems"
? "Workspace Problems"
: option.value === "URL" : option.value === "URL"
? "Paste URL to scrape" ? "Paste URL to scrape"
: option.value} : option.value}
@@ -95,11 +97,12 @@ const ContextMenu: React.FC<ContextMenuProps> = ({
{(option.value === "File" || option.value === "Folder") && ( {(option.value === "File" || option.value === "Folder") && (
<i className="codicon codicon-chevron-right" style={{ fontSize: "14px" }} /> <i className="codicon codicon-chevron-right" style={{ fontSize: "14px" }} />
)} )}
{(option.type === "file" || option.type === "folder") && {(option.type === "problems" ||
option.value !== "File" && ((option.type === "file" || option.type === "folder") &&
option.value !== "Folder" && ( option.value !== "File" &&
<i className="codicon codicon-add" style={{ fontSize: "14px" }} /> option.value !== "Folder")) && (
)} <i className="codicon codicon-add" style={{ fontSize: "14px" }} />
)}
</div> </div>
))} ))}
</div> </div>

View File

@@ -1,4 +1,5 @@
export const mockPaths = [ export const mockPaths = [
{ type: "problems", path: "Problems" },
{ type: "file", path: "/src/components/Header.tsx" }, { type: "file", path: "/src/components/Header.tsx" },
{ type: "file", path: "/src/components/Footer.tsx" }, { type: "file", path: "/src/components/Footer.tsx" },
{ type: "file", path: "/src/utils/helpers.ts" }, { type: "file", path: "/src/utils/helpers.ts" },
@@ -29,7 +30,7 @@ export function insertMention(text: string, position: number, value: string): st
} }
export function removeMention(text: string, position: number): { newText: string; newPosition: number } { export function removeMention(text: string, position: number): { newText: string; newPosition: number } {
const mentionRegex = /@(\/|\w+:\/\/)[^\s]+/ const mentionRegex = /@((?:\/|\w+:\/\/)[^\s]+|problems\b)/
const beforeCursor = text.slice(0, position) const beforeCursor = text.slice(0, position)
const afterCursor = text.slice(position) const afterCursor = text.slice(position)
@@ -73,6 +74,11 @@ export function getContextMenuOptions(
if (query === "") { if (query === "") {
return [ return [
{ type: "url", value: "URL", icon: "link" }, { type: "url", value: "URL", icon: "link" },
{
type: "problems",
value: "Problems",
icon: "warning",
},
{ type: "folder", value: "Folder", icon: "folder" }, { type: "folder", value: "Folder", icon: "folder" },
{ type: "file", value: "File", icon: "file" }, { type: "file", value: "File", icon: "file" },
] ]
@@ -93,12 +99,17 @@ export function getContextMenuOptions(
return matchingPaths.map((item) => ({ return matchingPaths.map((item) => ({
type: item.type, type: item.type,
value: item.path, value: item.path,
icon: item.type === "file" ? "file" : "folder", icon: item.type === "file" ? "file" : item.type === "problems" ? "warning" : "folder",
})) }))
} else { } else {
// If no matches, show all options // If no matches, show all options
return [ return [
{ type: "url", value: "URL", icon: "link" }, { type: "url", value: "URL", icon: "link" },
{
type: "problems",
value: "Problems",
icon: "warning",
},
{ type: "folder", value: "Folder", icon: "folder" }, { type: "folder", value: "Folder", icon: "folder" },
{ type: "file", value: "File", icon: "file" }, { type: "file", value: "File", icon: "file" },
] ]
@@ -120,6 +131,9 @@ export function shouldShowContextMenu(text: string, position: number): boolean {
// Don't show the menu if it's a URL // Don't show the menu if it's a URL
if (textAfterAt.toLowerCase().startsWith("http")) return false if (textAfterAt.toLowerCase().startsWith("http")) return false
// Don't show the menu if it's a problems
if (textAfterAt.toLowerCase().startsWith("problems")) return false
// Show the menu if there's just '@' or '@' followed by some text (but not a URL) // Show the menu if there's just '@' or '@' followed by some text (but not a URL)
return true return true
} }