Skip to content

Commit

Permalink
fix(ui): suppress mention menu when lacking source context (#3095)
Browse files Browse the repository at this point in the history
* fix(ui): suppress mention menu when lacking source context

* [autofix.ci] apply automated fixes

* update

* update

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
  • Loading branch information
liangfung and autofix-ci[bot] authored Sep 6, 2024
1 parent 47050b8 commit abde89b
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 60 deletions.
2 changes: 2 additions & 0 deletions ee/tabby-ui/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ function MainPanel() {
router.prefetch('/search')
}, [router])

// FIXME add loading skeleton
if (!healthInfo || !data?.me) return <></>

const onSearch = (question: string, ctx?: ThreadRunContexts) => {
Expand Down Expand Up @@ -157,6 +158,7 @@ function MainPanel() {
cleanAfterSearch={false}
contextInfo={contextInfoData?.contextInfo}
fetchingContextInfo={fetchingContextInfo}
className="min-h-[7rem]"
/>
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion ee/tabby-ui/app/search/components/search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ export function Search() {
>
<TextAreaSearch
onSearch={onSubmitSearch}
className="lg:max-w-4xl"
className="min-h-[5.5rem] lg:max-w-4xl"
placeholder="Ask a follow up question"
isLoading={isLoading}
isFollowup
Expand Down
150 changes: 94 additions & 56 deletions ee/tabby-ui/components/prompt-editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import './styles.css'

import React, { forwardRef, useImperativeHandle, useLayoutEffect } from 'react'
import React, {
forwardRef,
useEffect,
useImperativeHandle,
useLayoutEffect,
useMemo,
useState
} from 'react'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Placeholder from '@tiptap/extension-placeholder'
Expand All @@ -16,7 +23,7 @@ import {

import { ContextInfo, ContextSource } from '@/lib/gql/generates/graphql'
import { useLatest } from '@/lib/hooks/use-latest'
import { cn } from '@/lib/utils'
import { cn, isCodeSourceContext, isDocSourceContext } from '@/lib/utils'

import { MentionExtension } from './mention-extension'
import suggestion from './suggestion'
Expand Down Expand Up @@ -94,6 +101,7 @@ export const PromptEditor = forwardRef<PromptEditorRef, PromptEditorProps>(
},
ref
) => {
const [initialized, setInitialized] = useState(!fetchingContextInfo)
const doSubmit = useLatest((editor: Editor) => {
if (submitting) return

Expand All @@ -107,63 +115,87 @@ export const PromptEditor = forwardRef<PromptEditorRef, PromptEditorProps>(
doSubmit.current(editor)
}

const editor = useEditor({
immediatelyRender: false,
extensions: [
Document,
Paragraph,
Text,
Placeholder.configure({
placeholder: placeholder || 'Ask anything...'
}),
CustomKeyboardShortcuts(handleSubmit),
// for document mention
MentionExtension.configure({
deleteTriggerWithBackspace: true,
HTMLAttributes: {
class: 'mention'
},
suggestion: suggestion({
category: 'doc',
char: '@',
pluginKey: DocumentMentionPluginKey,
placement: placement === 'bottom' ? 'top-start' : 'bottom-start'
})
}),
// for codebase mention
MentionExtension.configure({
deleteTriggerWithBackspace: true,
HTMLAttributes: {
class: 'mention-code'
},
suggestion: suggestion({
category: 'code',
char: '#',
pluginKey: CodeMentionPluginKey,
placement: placement === 'bottom' ? 'top-start' : 'bottom-start'
const hasCodebaseSources = useMemo(() => {
if (!contextInfo?.sources) {
return false
}

return contextInfo.sources.some(o => isCodeSourceContext(o.kind))
}, [contextInfo?.sources])

const hasDocSources = useMemo(() => {
if (!contextInfo?.sources) {
return false
}

return contextInfo.sources.some(o => isDocSourceContext(o.kind))
}, [contextInfo?.sources])

const editor = useEditor(
{
editable: !initialized ? false : editable,
immediatelyRender: false,
extensions: [
Document,
Paragraph,
Text,
Placeholder.configure({
showOnlyWhenEditable: false,
placeholder: !initialized
? 'Loading...'
: placeholder || 'Ask anything...'
}),
CustomKeyboardShortcuts(handleSubmit),
// for document mention
MentionExtension.configure({
deleteTriggerWithBackspace: true,
HTMLAttributes: {
class: 'mention'
},
suggestion: suggestion({
category: 'doc',
char: '@',
pluginKey: DocumentMentionPluginKey,
placement: placement === 'bottom' ? 'top-start' : 'bottom-start',
disabled: !hasDocSources
})
}),
// for codebase mention
MentionExtension.configure({
deleteTriggerWithBackspace: true,
HTMLAttributes: {
class: 'mention-code'
},
suggestion: suggestion({
category: 'code',
char: '#',
pluginKey: CodeMentionPluginKey,
placement: placement === 'bottom' ? 'top-start' : 'bottom-start',
disabled: !hasCodebaseSources
})
})
})
],
editorProps: {
attributes: {
class: cn(
'max-h-38 prose min-h-[3.5rem] max-w-none font-sans dark:prose-invert focus:outline-none prose-p:my-0',
editorClassName
)
],
editorProps: {
attributes: {
class: cn(
'max-h-38 prose min-h-[3.5rem] max-w-none font-sans dark:prose-invert focus:outline-none prose-p:my-0',
editorClassName
)
}
},
content,
onBlur(props) {
onBlur?.(props)
},
onFocus(props) {
onFocus?.(props)
},
onUpdate(props) {
onUpdate?.(props)
}
},
content,
editable,
onBlur(props) {
onBlur?.(props)
},
onFocus(props) {
onFocus?.(props)
},
onUpdate(props) {
onUpdate?.(props)
}
})
[initialized]
)

useImperativeHandle(ref, () => ({
editor
Expand All @@ -175,6 +207,12 @@ export const PromptEditor = forwardRef<PromptEditorRef, PromptEditorProps>(
}
}, [editor])

useEffect(() => {
if (!fetchingContextInfo && !initialized) {
setInitialized(true)
}
}, [fetchingContextInfo])

if (!editor) {
return null
}
Expand Down
4 changes: 2 additions & 2 deletions ee/tabby-ui/components/prompt-editor/mention-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ const MetionList = forwardRef<MentionListActions, MetionListProps>(
/>
))
) : (
<div className="px-2 py-1.5">
<div className="px-2 py-1.5 text-sm text-muted-foreground">
{options?.length ? (
<span>No matches results</span>
) : (
<span>No results, please configure in Context Providers</span>
<span>No results</span>
)}
</div>
)}
Expand Down
13 changes: 13 additions & 0 deletions ee/tabby-ui/components/prompt-editor/suggestion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,13 @@ const getMentionsFromEditor = (editor: Editor) => {
}

const suggestion: (options: {
disabled?: boolean
category: 'doc' | 'code'
placement?: Placement
pluginKey: PluginKey
char?: string
}) => MentionOptions['suggestion'] = ({
disabled,
category,
placement,
char = '@',
Expand Down Expand Up @@ -144,6 +146,17 @@ const suggestion: (options: {

// get reference to `window` object from editor element, to support cross-frame JS usage
editor.view.dom.ownerDocument.defaultView?.getSelection()?.collapseToEnd()
},
allow: ({ state, range }) => {
if (disabled) {
return false
}

const $from = state.doc.resolve(range.from)
const type = state.schema.nodes[MENTION_EXTENSION_NAME]
const allow = !!$from.parent.type.contentMatch.matchType(type)

return allow
}
})

Expand Down
4 changes: 3 additions & 1 deletion ee/tabby-ui/components/textarea-search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ export default function TextAreaSearch({
onSubmit={handleSubmit}
placeholder={
placeholder ||
'Ask anything...\n\nUse # to select a codebase to chat with, or @ to select a document to bring into context.'
(contextInfo?.sources?.length
? 'Ask anything...\n\nUse # to select a codebase to chat with, or @ to select a document to bring into context.'
: 'Ask anything...')
}
autoFocus={autoFocus}
onFocus={() => setIsFocus(true)}
Expand Down

0 comments on commit abde89b

Please sign in to comment.